【问题标题】:Increment ID in ParallelQuery.ForAll MethodParallelQuery.ForAll 方法中的增量 ID
【发布时间】:2012-08-27 23:51:03
【问题描述】:

我有一个需要同时处理的文件列表。我尝试使用 ParallelQuery 类的 ForAll 扩展方法。我没有按顺序处理文件,所以我使用了 ForAll。

这是我的示例代码:

List<FileInfo> files = GetFilesToProcess();

files.AsParallel().ForAll(f => { // Process file here });

效果很好,但现在我需要为每个文件生成一个唯一的整数 ID,如果不将 AsParallel.ForAll 更改为 ForEach,我不知道该怎么做。

我在某个地方读到了需要作为联锁的地方,但仍然会有问题。

希望你能在这里给我一个想法。

谢谢!

【问题讨论】:

    标签: c#-4.0 parallel-processing forall


    【解决方案1】:

    可以使用Interlocked.Increment生成ID,也可以直接使用索引:

    List<FileInfo> files = GetFilesToProcess();
    
    files.AsParallel().Select((f, i) => new {File=f, ID=i})
         .ForAll(fp => 
               {
                  FileInfo file = fp.File;
                  int id = fp.ID; // ID is the index in the list
    
                  // Process file here
               });
    

    如果你想使用Interlocked.Increment,你可以这样做:

    List<FileInfo> files = GetFilesToProcess();
    int globalId = -1;
    
    files.AsParallel().ForAll(f => 
                             { 
                                  // Process file here 
                                  int id = Interlocked.Increment(ref globalId);
                                  // use ID
                             });
    

    话虽如此,如果您的整个目标是对集合进行“工作”,我建议将其编写为 Parallel.For 或 Parallel.ForEach。这更清楚,因为您使用 LINQ 样式语法的唯一目的不是产生副作用:

    List<FileInfo> files = GetFilesToProcess();
    Parallel.For(0, files.Count, i =>
    {
        var file = files[i];
        // Use i and file as needed
    });
    

    【讨论】:

    • 嗨 Reed,感谢您提出的解决方案和回复。我想澄清一下,如果我使用 Parallel For/ForEach,它会像在 ForAll 中一样并行执行吗?抱歉,如果您认为这是一个愚蠢的问题。只是想确定一下。
    • @lionheart 是的 - 这是两种不同的方法。通常,如果您正在执行某种形式的过滤操作 (.Where) 或映射操作 (.Select),您将使用 PLINQ (.AsParallel())。刚刚引入了.ForAll() 方法,以便在您处理“查询”的结果时进行简化。如果您的目标仅仅是“并行做一些工作”,那么Parallel.ForParallel.ForEach 更合适。有关原因的一个很好的论据,请阅读:blogs.msdn.com/b/ericlippert/archive/2009/05/18/…
    【解决方案2】:

    如果你真的需要,那么你可以通过Interlocked.Increment 处理一个int

    使用源的索引是更好的选择,因为分区器已经提供了这些信息,即使像Interlocked 提供的轻共享,仍然是共享的。

    或者,您可以跳过它并使用某种 UUID。在这种情况下,这可能是值得的(获得索引既好又轻)。我之所以提到它,是因为“我可以在并行任务之间零共享的情况下做到这一点吗?”应始终考虑,即使以后被解雇。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-08
      • 1970-01-01
      • 2017-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多