Can we add new elements to a list using Parallel.ForEach()?

半腔热情 提交于 2019-12-05 17:12:28

What you would really want in this situation is more like this:

newlist = list.AsParallel().Select(l => new DateTime(l.Ticks + 5000)).ToList();

Although you should measure the performance to see if this situation even benefits from parallelization.

Try a thread local variable with a final result that adds all thread local variables to the newList as such...

Parallel.ForEach(list, () => DateTime.MinValue, (l, state, date) =>
{
    date = new DateTime(l.Ticks+5000);
    return date;
},
finalresult =>
{
   lock (newList)
   {
       newList.Add(finalresult);
   }
});

The first param is your old list the second Param is the initial value of each thread (I just initialized to datetime min). the third param block is as follows- the l is the same as in your code; the state is a Paralleloption object of which you can exit out of parallel loop if you choose; the last is the stand in variable that represents the thread local variable. The finalresult param represents the end result of each thread local variable and is called for each thread - it is there you can place a lock of the newList and add to the newList shared variable. In theory this works. I have used similar coding in my own code. Hope this helps you or someone else.

As everyone has mentioned, there seems to be no case for doing this parallel. It will certainly be far, far slower. However, for completion, the reason this sometimes fails is there is no lock on the list object that's being written to by multiple threads. Add this:

object _locker = new object();
List<DateTime> newList = new List<DateTime>();
Parallel.ForEach(list, l => lock (_locker) newlist.Add(new DateTime(l.Ticks + 5000)));

There simply is not enough work to do for this to warrant using Parallel.ForEach and also List<T> is not thread safe, so you would have to lock if you wanted to add to the same list in parallel. Just use a regular for loop.

This will effectively call List<T>.Add concurrently, yet according to MSDN documentation for List<T>:

"Any instance members are not guaranteed to be thread safe."

Even if it were (thread safe), this is far too cheap to benefit from parallel execution (as opposed to overhead of parallel execution). Did you actually measure your performance? 25000 elements is not that many.

Do you really need these in a list? If all you need is to enumerate the list in a foreach, you should probably do this instead, as it will use far less memory:

IEnumerable<DateTime> newSequence = list.Select(d => new DateTime(d.Ticks + 5000));

If you really need these in a list, just add .ToList() at the end:

var newSequence = list.Select(d => new DateTime(d.Ticks + 5000)).ToList();

This will almost certainly be fast enough that you don't need to parallelize it. In fact, this is probably faster than doing it in parallel, as it will have better memory performance.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!