• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 208
  • Last Modified:

Problem with Parallel.For

Hello,

I have a simular problem...

When I execute the following code, the program not always creates all objects in the loop and finally exits with different number of objects created.

First time 39995, second 40000, third 39988, ...

Is there a way to explain this?



        private void button2_Click(object sender, EventArgs e)
        {
            _calcObjects.Clear();

            long startTime = DateTime.Now.Ticks;

            Parallel.For(0, 200, i =>
            {
                for (int j = 0; j < 200; j++)
                    _calcObjects.Add(new CalculateObject { X = i + 1, Y = j + 1 });
            });
           
            long endTime = DateTime.Now.Ticks;

            this.lblResult1.Text = ((endTime - startTime) / 1000).ToString("#0.00") + " : " + _calcObjects.Count.ToString() + " objects created";

       

        }

0
TLFINFRONT
Asked:
TLFINFRONT
  • 4
  • 3
  • 2
1 Solution
 
TommySzalapskiCommented:
The Add method of whatever _calcObjects is most likely is not thread safe.
This means that every once in a while, two threads try to update it at the same time and both think they did, but only one really got added.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
I'm guessing "_calcObjects" is a List<CalculateObject>?

If so, read...
http://stackoverflow.com/questions/5589315/list-add-thread-safety
http://msdn.microsoft.com/en-us/library/dd997305.aspx
http://msdn.microsoft.com/en-us/library/dd997371.aspx

Example:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private BlockingCollection<Object> MyObjects = new BlockingCollection<Object>(400000);

        private void button1_Click(object sender, EventArgs e)
        {
            MyObjects = new BlockingCollection<Object>(400000);

            long startTime = DateTime.Now.Ticks;

            ParallelLoopResult plr = Parallel.For(0, 200, i =>
            {
                for (int j = 0; j < 200; j++)
                    MyObjects.Add(new Object());
            });

            Console.WriteLine("IsCompleted = " + plr.IsCompleted.ToString());

            long endTime = DateTime.Now.Ticks;

            this.label1.Text = ((endTime - startTime) / 1000).ToString("#0.00") + " : " + MyObjects.Count.ToString() + " objects created";
        }

    }
}

Open in new window

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Ha!...Hi Tommy.  =)
0
Prepare for your VMware VCP6-DCV exam.

Josh Coen and Jason Langer have prepared the latest edition of VCP study guide. Both authors have been working in the IT field for more than a decade, and both hold VMware certifications. This 163-page guide covers all 10 of the exam blueprint sections.

 
TommySzalapskiCommented:
What is the type of _calcObjects?

When you are doing multithreading (which is what the parallel for does) each thread runs at the same time as the other threads. If there is a shared resource that they all utilize (in this case _calcObjects) then you need to have some structures in place to guarantee that they don't conflict with more than one try to edit it at the same time (like mutual exclusion).

If something has good mutual exclusion and semaphores, etc so that multiple threads can all share it without the chance of problems, that thing is called "thread safe".
My guess is that _calcObject.Add() is not thread safe and this is why it doesn't always work right.
0
 
TommySzalapskiCommented:
Ooh, good call Idle_Mind. I'm not very experienced with C# (the Algorithms zone is why I'm here). So that's how you make it thread safe then.
0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
With the original List<> (if that's what it was) you can synchronize it using "lock"...but I don't know if this is detrimental to the Parallel approach...?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private List<Object> MyObjects = new List<Object>();

        private void button1_Click(object sender, EventArgs e)
        {
            MyObjects.Clear();

            long startTime = DateTime.Now.Ticks;

            ParallelLoopResult plr = Parallel.For(0, 200, i =>
            {
                for (int j = 0; j < 200; j++)
                {
                    lock (MyObjects)
                    {
                        MyObjects.Add(new Object());
                    }
                }
            });

            Console.WriteLine("IsCompleted = " + plr.IsCompleted.ToString());

            long endTime = DateTime.Now.Ticks;

            this.label1.Text = ((endTime - startTime) / 1000).ToString("#0.00") + " : " + MyObjects.Count.ToString() + " objects created";
        }

    }
}

Open in new window

0
 
Mike TomlinsonMiddle School Assistant TeacherCommented:
Said differently...I don't know if List<> with "lock" is better or worse than BlockingCollection<>.
0
 
TLFINFRONTAuthor Commented:
Hello!

Thanks for you fast reply. _cakcObjects is indeed a List<CalculateObjects>, a class that I defined for educational reasons.

Using the 'lock' keyword indeed solves the problem but it really downgrades performance and is slower than a regular for loop. But this is indeed the correct answer. The add method of the list is in this case not threadsafe.

I also tried using the blockingcollection and that increases performance a lot!

Blockincollection is the way to go!

Thanks!

Tom

0
 
TLFINFRONTAuthor Commented:
Great!

Thanks!
0

Featured Post

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

  • 4
  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now