如果源为空,Parallel.ForEach是否启动线程?

时间:2018-02-12 12:08:47

标签: c# task-parallel-library

我以这种方式使用Parallel.ForEach

public void myMethod(IEnumerable<MyType> paramIeCollection)
{
    Parallel.Foreach(paramIeCollection,
          (iterator) =>
          {
              //Do something
          });
}

我想知道当paramIeCollection为空时,Parallel.ForEach无论如何都会启动并从线程池获取线程并消耗资源,或者如果它首先检查集合中是否有项目。

如果没有检查,为了避免这种情况,我在想这个代码:

if(paramIeCollection.count > 0)
{
    //run Parallel.Foreach
}

所以问题是,在调用Parallel.ForEach之前检查集合是否包含项目或者是否需要它是否是一个好习惯?

2 个答案:

答案 0 :(得分:9)

事实是确实它确实检查。但是,如果您通过源代码,那么在它出现之前会有一些其他的检查和平衡

如果你有处理器指令OCD ,事先像if(list.count > 0)那样的简单检查可能会为你节省一堆IL。然而,在现实世界中,它不会产生太大的影响

System.Threading.Tasks Reference Source

例如,对于简单IEnumberable重载,您可以通过E.g

关注源代码
public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, Action<TSource> body)

致电ForEachWorker

private static ParallelLoopResult ForEachWorker<TSource, TLocal>(
        IEnumerable<TSource> source,
        ParallelOptions parallelOptions,
        Action<TSource> body,
        Action<TSource, ParallelLoopState> bodyWithState,
        Action<TSource, ParallelLoopState, long> bodyWithStateAndIndex,
        Func<TSource, ParallelLoopState, TLocal, TLocal> bodyWithStateAndLocal,
        Func<TSource, ParallelLoopState, long, TLocal, TLocal> bodyWithEverything,
        Func<TLocal> localInit, Action<TLocal> localFinally)

内联呼叫

// This is an honest-to-goodness IEnumerable.  Wrap it in a Partitioner and defer to our
        // ForEach(Partitioner) logic.
return PartitionerForEachWorker<TSource, TLocal>(Partitioner.Create(source), parallelOptions, body, bodyWithState,
            bodyWithStateAndIndex, bodyWithStateAndLocal, bodyWithEverything, localInit, localFinally);

PartitionerForEachWorker

// Main worker method for Parallel.ForEach() calls w/ Partitioners.
private static ParallelLoopResult PartitionerForEachWorker<TSource, TLocal>(
        Partitioner<TSource> source, // Might be OrderablePartitioner
        ParallelOptions parallelOptions,
        Action<TSource> simpleBody,
        Action<TSource, ParallelLoopState> bodyWithState,
        Action<TSource, ParallelLoopState, long> bodyWithStateAndIndex,
        Func<TSource, ParallelLoopState, TLocal, TLocal> bodyWithStateAndLocal,
        Func<TSource, ParallelLoopState, long, TLocal, TLocal> bodyWithEverything,
        Func<TLocal> localInit,
        Action<TLocal> localFinally)

最终检查

while (myPartition.MoveNext())

答案 1 :(得分:2)

Parallel.ForEach将在内部调用IEnumerator.MoveNext(),这将在空集合上返回false,因此不会执行任何工作。
虽然直接检查集合是否为空是更快,但差异可能微不足道。