Parallel.ForEach() Vs Foreach() Loop in C#

Foreach loop

Foreach loop runs upon a single thread and processing takes place sequentially one by one. Foreach loop is a basic feature of C# and it is available from C# 1.0. Its execution is slower than Parallel.Foreach in most of the cases.

Parallel.ForEach loop

Parallel.ForEach loop runs upon multiple threads and processing takes place in a  parallel way. Parallel.ForEach loop is not a basic feature of C# and it is available from C# 4.0 and above. Before C# 4.0 we cannot use it. Its execution is faster than foreach in most of the cases. To use Parallel.ForEach loop we need to import System.Threading.Tasks namespace in using directive.

But you know your application well and you can decide which one you want to use.

I am giving 2 examples, in the first example traditional foreach loop is faster than Parallel.foreach loop where as in second example traditional foreach loop is very slow as compared to Parallel.foreach.

Example 1: Parallel.ForEach loop is slower than Traditional Foreach loop.

  1. List<string> fruits = new List<string>();  
  2.   fruits.Add("Apple");  
  3.   fruits.Add("Banana");  
  4.   fruits.Add("Bilberry");  
  5.   fruits.Add("Blackberry");  
  6.   fruits.Add("Blackcurrant");  
  7.   fruits.Add("Blueberry");  
  8.   fruits.Add("Cherry");  
  9.   fruits.Add("Coconut");  
  10.   fruits.Add("Cranberry");  
  11.   fruits.Add("Date");  
  12.   fruits.Add("Fig");  
  13.   fruits.Add("Grape");  
  14.   fruits.Add("Guava");  
  15.   fruits.Add("Jack-fruit");  
  16.   fruits.Add("Kiwi fruit");  
  17.   fruits.Add("Lemon");  
  18.   fruits.Add("Lime");  
  19.   fruits.Add("Lychee");  
  20.   fruits.Add("Mango");  
  21.   fruits.Add("Melon");  
  22.   fruits.Add("Olive");  
  23.   fruits.Add("Orange");  
  24.   fruits.Add("Papaya");  
  25.   fruits.Add("Plum");  
  26.   fruits.Add("Pineapple");  
  27.   fruits.Add("Pomegranate");  
  28.   
  29.   Console.WriteLine("Printing list using foreach loop\n");  
  30.   
  31.   var stopWatch = Stopwatch.StartNew();  
  32.   foreach (string fruit in fruits)  
  33.   {  
  34.       Console.WriteLine("Fruit Name: {0}, Thread Id= {1}", fruit, Thread.CurrentThread.ManagedThreadId);  
  35.   }  
  36.   Console.WriteLine("foreach loop execution time = {0} seconds\n", stopWatch.Elapsed.TotalSeconds);  
  37.   Console.WriteLine("Printing list using Parallel.ForEach");  
  38.   
  39.   
  40.   stopWatch = Stopwatch.StartNew();  
  41.   Parallel.ForEach(fruits, fruit =>  
  42.   {  
  43.       Console.WriteLine("Fruit Name: {0}, Thread Id= {1}", fruit, Thread.CurrentThread.ManagedThreadId);  
  44.   
  45.   }  
  46.   );  
  47.   Console.WriteLine("Parallel.ForEach() execution time = {0} seconds", stopWatch.Elapsed.TotalSeconds);  
  48.   Console.Read();  
Output

Execution time

Output

Example 2: Parallel.ForEach loop is faster than Traditional Foreach loop.

Traditional Foreach
  1. var stopWatch = Stopwatch.StartNew();  
  2. PointF firstLocation = new PointF(10 f, 10 f);  
  3. PointF secondLocation = new PointF(10 f, 50 f);  
  4. foreach(string file in Directory.GetFiles(@ "D:\Images"))  
  5. {  
  6.     Bitmap bitmap = (Bitmap) Image.FromFile(file);  
  7.     using(Graphics graphics = Graphics.FromImage(bitmap))  
  8.     {  
  9.         using(Font arialFont = new Font("Arial", 10))  
  10.         {  
  11.             graphics.DrawString("Banketeshvar", arialFont, Brushes.Blue, firstLocation);  
  12.             graphics.DrawString("Narayan", arialFont, Brushes.Red, secondLocation);  
  13.         }  
  14.     }  
  15.     bitmap.Save(Path.GetDirectoryName(file) + "Foreachloop" + "\\" + Path.GetFileNameWithoutExtension(file) + Guid.NewGuid()  
  16.         .ToString() + ".jpg");  
  17. }  
  18. Console.WriteLine("foreach loop execution time = {0} seconds\n", stopWatch.Elapsed.TotalSeconds);  
Output

cmd


Parallel.foreach
  1. var stopWatch = Stopwatch.StartNew();  
  2. PointF firstLocation = new PointF(10 f, 10 f);  
  3. PointF secondLocation = new PointF(10 f, 50 f);  
  4. Parallel.ForEach(Directory.GetFiles(@ "D:\Images"), file =>  
  5. {  
  6.     Bitmap bitmap = (Bitmap) Image.FromFile(file);  
  7.     using(Graphics graphics = Graphics.FromImage(bitmap))  
  8.     {  
  9.         using(Font arialFont = new Font("Arial", 10))  
  10.         {  
  11.             graphics.DrawString("Banketeshvar", arialFont, Brushes.Blue, firstLocation);  
  12.             graphics.DrawString("Narayan", arialFont, Brushes.Red, secondLocation);  
  13.         }  
  14.     }  
  15.     bitmap.Save(Path.GetDirectoryName(file) + "Parallel" + "\\" + Path.GetFileNameWithoutExtension(file) + Guid.NewGuid()  
  16.         .ToString() + ".jpg");  
  17. });  
  18. Console.WriteLine("Parallel.ForEach() execution time = {0} seconds", stopWatch.Elapsed.TotalSeconds);  
  19. Console.Read();  
Output

run


To test the performance of the above code I have used around 150 images in both cases.

You can see that if you are doing any bulk task inside the foreach loop then parallel.foreach is very fast so you can go for parallel.foreach. But if you just iterating and doing a very little task inside loop then go for traditional for loop.