【问题标题】:Thread Index in PLINQ Query?PLINQ 查询中的线程索引?
【发布时间】:2010-11-02 12:25:01
【问题描述】:

有没有办法将 PLINQ 查询的线程“索引”传递给它的一个运算符,如 Select?

背景是我有一个 PLINQ Query 进行一些反序列化,反序列化方法使用一个结构(可能是一个数组)将数据传递给另一个方法:

      ParallelEnumerable.Range(0, nrObjects)
        .WithDegreeOfParallelism(8)
        .Select(i => this.Deserialize(serializer, i, arrays[threadIndex]))
        .ToList();

(threadIndex 是我想要的新变量)

如果我知道线程索引,我可以预先创建 8 个这样的数组(即使所有可能都不会使用)并重用它们。反序列化方法可能会被调用数百万次,因此每个小的优化都很重要。

【问题讨论】:

  • 我不明白你为什么不能使用i?它将在计算中是唯一的
  • @Andrey - 如果我的意图正确,他希望安全地重新使用少量工作缓冲区进行操作。
  • @Marc Gravell♦ 你是对的,我仔细阅读了问题
  • 是的,完全正确:) 在这里缓冲区可能是错误的词,它只是一个小数组,正如我所说的,微优化

标签: c# .net plinq


【解决方案1】:

重新线程索引;请注意,并行度是 (IIRC) 仅 最大 要使用的线程数;它没有使用那个号码。以您描述的方式依赖threadIndex 似乎意味着您可能实际上只能访问arrays[0]。简而言之,不:我不这么认为。

但是,您可以获得 item 索引;所以如果这就是你的意思,简单地说:

.Select((value, itemIndex) => this.Deserialize(
     serializer, i, arrays[itemIndex])).ToList();

听起来 (cmets) 的目的是为了获得一个工作缓冲区;在这种情况下,我会(实际上,)在容器中保留一些方便的缓冲区(具有同步访问等),即

  • 尝试从容器中获取现有缓冲区(同步)
  • 如果没有找到,创建一个新的缓冲区
  • (做工作)
  • 向容器返回/添加缓冲区(同步)

这通常会非常快(比每次迭代的缓冲区分配快得多)

【讨论】:

  • 是的,我知道...但是如果只重复使用一个数组并同时使用,那没关系。只需要避免不同线程使用相同的数组
  • @MattiasK - 我猜这是一个暂存缓冲区,对吧?
  • 是的 :) 我不想为每个项目创建一个数组,这有点违背了目的。我正在尝试让反序列化方法将每个字段打包到一个数组中,该数组被发送到设置对象值的适配器。我正在尽量减少演员阵容,所以这并不容易:)
  • 在这种情况下,我不能真正使用同步或其他线程机制,因为它比创建数组需要更多时间(我们说的是(2-8 项数组,所以它处于纳米级) :)
【解决方案2】:

您可以创建ConcurrentBag 的整数,然后在解散之前从中取出用作索引,然后返回。每个线程一次将占用一个数组元素。

考虑使用Parallel class。当涉及到数组时,它更合适。如果您使用ParallelEnumerable,则Select 的索引版本存在限制(不是您的情况,但要小心)

【讨论】:

  • 我尝试过使用 Parallel 和 ConcurrentBag,但在这种情况下,当被调用的方法只需要很少的时间但被多次调用时,性能就太差了(我已经测量过了)
【解决方案3】:

我建议使用Parallel.ForEach which offers an overload that allows you to allocate (and cleanup) locals,它将一次传递到循环的一个并行实例中。我已经使用这种方法来处理大量图像数据集,其中我需要缓冲区用于处理的各个步骤。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多