【问题标题】:Equivalent of do() while{} in Parallel等效于 do() while{} 并行
【发布时间】:2011-11-16 00:55:43
【问题描述】:

如何在下面的 Update() 方法中创建 do-while 或类似的并行等效项?

应用程序中的另一个线程随机写入TestBufferTestBuffer.RemoveItemAndDoSomethingWithIt(); 应该一直运行到 TestBuffer 为空。目前Update() 仅与枚举时集合中的项目一起运行,这是有道理的。

internal class UnOrderedBuffer<T> where T : class
{
    ConcurrentBag<T> GenericBag = new ConcurrentBag<T>();
}

internal class Tester
{
    private UnOrderedBuffer<Data> TestBuffer;

    public void Update()
    {
        Parallel.ForEach(TestBuffer, Item =>
        {
            TestBuffer.RemoveItemAndDoSomethingWithIt();
        });
    }
}

【问题讨论】:

  • 你的意图是什么?您是希望多个线程处理 TestBuffer 还是要在后台线程中异步处理 TestBuffer。
  • TestBuffer 应该使用可用的内核尽快清空。

标签: c# parallel-processing plinq


【解决方案1】:

您可以通过“添加”一个空值/默认值来强制执行一次:

static IEnumerable<T> YieldOneDefault<T>(this IEnumerable<T> values)
{
    yield return default(T);
    foreach(var item in values)
        yield return item;
}

然后按如下方式使用:

Parallel.ForEach(TestBuffer.YieldOneDefault(), Item =>  
{  
    if(Item != null)
      TestBuffer.RemoveItemAndDoSomethingWithIt();
    else
      DoSomethingDuringTheFirstPass();
});  

虽然我怀疑您可能正在寻找以下扩展方法:

public static IEnumerable<IEnumerable<T>> GetParrallelConsumingEnumerable<T>(this IProducerConsumerCollection<T> collection)
{
    T item;
    while (collection.TryTake(out item))
    {
        yield return GetParrallelConsumingEnumerableInner(collection, item);
    }
}

private static IEnumerable<T> GetParrallelConsumingEnumerableInner<T>(IProducerConsumerCollection<T> collection, T item)
{
    yield return item;
    while (collection.TryTake(out item))
    {
        yield return item;
    }
}

这会让你得到这个结果(我认为这就是你所追求的):

Parallel.ForEach(TestBuffer.GetParrallelConsumingEnumerable(), Items =>       
{
    foreach(var item in Items)
    {
       DoSomethingWithItem(item);
    }
});

【讨论】:

  • 据我了解,OP 正在寻找的答案是您编写的第一个扩展方法。
  • @Jonathan Dickinson 尝试了您的建议并得到“错误 1 ​​扩展方法必须在非泛型静态类中定义”。
  • @Canacourse - 错误说明了什么?提示:它告诉你如何定义扩展方法。
  • 我错误地认为您的代码是用于 UnorderedBuffer 类的。感谢您的回答(和提示)
【解决方案2】:

for/foreach 通常用于对多个项目执行任务。

while-do/do-while 用于:

一个。对多个项目执行任务 尚未枚举的(例如一棵树)。
- 在这种情况下,您可以定义 BFS 或 DFS 枚举器并在 foreach 中使用。

b.对单个项目执行迭代工作
- 迭代工作不适合并行性

不要尝试将代码从串行重构为并行。相反,请考虑您的任务是什么以及如何最好地并行完成。 (重构算法,而不是代码。)

【讨论】:

    【解决方案3】:
    public static void While( 
        ParallelOptions parallelOptions, Func<bool> condition, 
        Action<ParallelLoopState> body) 
    { 
        Parallel.ForEach(Infinite(), parallelOptions, (ignored, loopState) => 
        { 
            if (condition()) body(loopState); 
            else loopState.Stop(); 
        }); 
    }
    
    private static IEnumerable<bool> Infinite() 
    { 
        while (true) yield return true; 
    }
    

    【讨论】:

    • 请添加一些关于您想要达到的目标的信息
    猜你喜欢
    • 2016-10-06
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2019-06-15
    • 1970-01-01
    • 2016-07-19
    相关资源
    最近更新 更多