代码之家  ›  专栏  ›  技术社区  ›  Álvaro García

是平行的。如果源为空,ForEach启动线程?

  •  5
  • Álvaro García  · 技术社区  · 8 年前

    我正在使用 Parallel.ForEach 以这种方式:

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

    我想知道什么时候 paramIeCollection 为空,则 平行的ForEach公司 无论如何都要启动并从线程池中获取线程并消耗资源,或者它是否首先检查集合中是否有项。

    如果没有检查,为了避免出现这种情况,我在下面的代码中考虑:

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

    所以问题是,在调用之前检查集合是否有项目是一种好的做法吗 平行的ForEach公司 或者如果不需要的话?

    2 回复  |  直到 8 年前
        1
  •  9
  •   marc_s MisterSmith    5 年前

    要知道真相,它确实起作用。然而,如果你仔细查看来源,还有其他一些 检查和平衡 在它弄明白之前就知道了。

    如果你有 处理器指令OCD ,一个简单的预先检查,如 if(list.count > 0) 可能会帮你省下一大笔钱。然而,在现实世界中,这不会有多大区别

    System.Threading.Tasks Reference Source

    例如,对于简单的 IEnumerable 重载,您可以按照源代码进行操作,例如

    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())
    
        2
  •  3
  •   Camilo Terevinto Chase R Lewis    8 年前

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