实现并行无限循环的最佳方法是什么?
我已经习惯在 .NET 并行扩展中使用 Parallel.For() ,因为这是一种并行化代码的简单方法,而无需手动启动和维护线程(这可能很繁琐)。我现在正在查看一个无限循环(执行某些操作,直到我发出信号停止),我希望并行化,没有无参数的 Parallel.For()
重载来执行此操作,所以是想知道这里最好的方法是什么。原则上我可以做类似的事情:
Parallel.For(0, int.Max)
但我怀疑这可能不是工作分区逻辑处理的预期/有效模式(?)
另一种选择是这样的:
for(;;)
{
Parallel.For(0, 128, delegate()
{
// Do stuff.
}
}
但这看起来不优雅,也可能导致工作效率低下分区。
现在我的本能是通过创建和维护自己的线程来手动完成此操作,但我有兴趣获得一些对此的反馈/意见。谢谢。
===更新===
我正在使用接受的答案中文章中的代码的简化版本(我已删除 ParallelOptions
参数)。这是代码...
public class ParallelUtils
{
public static void While(Func<bool> condition, Action body)
{
Parallel.ForEach(IterateUntilFalse(condition), ignored => body());
}
private static IEnumerable<bool> IterateUntilFalse(Func<bool> condition)
{
while (condition()) yield return true;
}
}
示例用法是:
Func<bool> whileCondFn = () => !_requestStopFlag;
ParallelUtils.While(whileCondFn, delegate()
{
// Do stuff.
});
I've gotten used to using Parallel.For()
in .NET's parallel extensions as it's a simple way of parallelizing code without having to manually start and maintain threads (which can be fiddly). I'm now looking at an infinite loop (do something until I signal it to stop) that I wish to parallelize, there isn't an argument free Parallel.For()
overload to do this so was wondering what the best approach here would be. In principle I could just do something like:
Parallel.For(0, int.Max)
But I'm suspecting that might not be an expected/efficient pattern for the work partitioning logic to handle(?)
Another option is something like:
for(;;)
{
Parallel.For(0, 128, delegate()
{
// Do stuff.
}
}
But that seems inelegant and may also result in inefficient work partitioning.
Right now my instinct is to do this manually by creating and maintaining my own threads, but I would be interested in getting some feedback/opinions on this. Thanks.
=== UPDATE ===
I'm using a simplified version of the code from the article in the accepted answer (I've removed the ParallelOptions
parameter). Here's the code...
public class ParallelUtils
{
public static void While(Func<bool> condition, Action body)
{
Parallel.ForEach(IterateUntilFalse(condition), ignored => body());
}
private static IEnumerable<bool> IterateUntilFalse(Func<bool> condition)
{
while (condition()) yield return true;
}
}
An example usage would be:
Func<bool> whileCondFn = () => !_requestStopFlag;
ParallelUtils.While(whileCondFn, delegate()
{
// Do stuff.
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果你(真的)想要无限的东西,那么你希望它在尽可能少的核心上。
Parallel.For___
都不是一个好的选择。您(可能)需要的是使用 LongRunning 选项创建的单独线程或任务。
然后让它等待信号量,或者作为最后的手段尽可能频繁地调用 Sleep()。
If you (really) want something infinite then you want it on as few cores a possible. None of the
Parallel.For___
would be a good choice.What you (probably) need is a separate Thread or a Task created with the LongRunning option.
And then make it wait on a semaphore, or as a last resort call Sleep() as often as possible.
考虑到它是无限微积分请求,但您需要在每个“周期”上有一些有限状态,我想说我会使用外部
for(;;)
循环更改解决方案来执行Parallel.ForEach(...)
调用某些事件/状态更改。就像Monitor
信号、event
通知或类似的东西......Considering that it's infinit calculus request, but you need to have some finit state on every "cycle", I would say that I would change a solution with an external
for(;;)
loop to execute aParallel.ForEach(...)
call on some event/state change. Like aMonitor
signal,event
notification, or something like that...这是 ParallelWhile 方法的现代实现,该方法基于
Parallel.For
,并且与 Stephen Toub 的实现 从 2009 年开始。主要区别在于 Parallel.For 对每个工作线程执行一次迭代,而不是枚举无限序列。然后,每个线程在内部
while
循环中重复调用body
。这样,与包含虚拟元素的序列交互(缓冲/同步等)的开销就被消除了。如果body
非常轻量级,则此开销可能会很大。ParallelWhile
支持Parallel.For
循环的所有选项,并且在发生异常和取消时具有相同的行为。它还保留的语义MaxDegreeOfParallelism
选项,当它具有默认值-1
时,这意味着无限的并行性,实际上意味着“使用所有可用的并行度”ThreadPool
线程”。我总是赞成显式指定 MaxDegreeOfParallelism,并给它一个合理的值。在大多数情况下,此值是Environment.ProcessorCount
。使
ThreadPool
饱和会产生许多不良副作用,并且几乎没有带来任何好处(如果有的话)。使用示例:
Here is a modern implementation of a
ParallelWhile
method, which is based on theParallel.For
, and has identical signature with Stephen Toub's implementation from 2009.The main difference is that the
Parallel.For
executes one iteration per worker-thread, instead of enumerating an infinite sequence. Then each thread invokes thebody
repeatedly in an innerwhile
loop. This way the overhead of interacting (buffering/synchronizing etc) with a sequence that contains dummy elements is eliminated. This overhead can be significant in case thebody
is very lightweight.The
ParallelWhile
supports all the options of theParallel.For
loop, and it has the same behavior in case of exceptions and cancellation. It also retains the semantics of theMaxDegreeOfParallelism
option when it has the default value-1
, which means unlimited parallelism, and in practice means "use all the availableThreadPool
threads". I am always in favor of specifying explicitly theMaxDegreeOfParallelism
, and giving it a reasonable value. In most cases this value isEnvironment.ProcessorCount
. Saturating theThreadPool
has many undesirable side-effects, and offers few benefits, if any, in return.Usage example:
我发现了这个技巧
https://dejanstojanovic.net/aspnet/2015/september /parallel-infinite-loop-in-c/
i found this trick
https://dejanstojanovic.net/aspnet/2015/september/parallel-infinite-loop-in-c/