如何从并行任务产生在.NET 4.5 [英] How to yield from parallel tasks in .NET 4.5
问题描述
我想用.NET迭代器并行任务/等待?事情是这样的:
I would like to use .NET iterator with parallel Tasks/await?. Something like this:
IEnumerable<TDst> Foo<TSrc, TDest>(IEnumerable<TSrc> source)
{
Parallel.ForEach(
source,
s=>
{
// Ordering is NOT important
// items can be yielded as soon as they are done
yield return ExecuteOrDownloadSomething(s);
}
}
不幸的是.NET本身不能处理这个问题。最好的答案迄今@svick - 使用进行AsParallel()
Unfortunately .NET cannot natively handle this. Best answer so far by @svick - use AsParallel().
奖金:任何简单的异步/等待code实现多个出版商和单个用户?订户将产生,而酒吧将处理。 (唯一的核心库)
BONUS: Any simple async/await code that implements multiple publishers and a single subscriber? The subscriber would yield, and the pubs would process. (core libraries only)
推荐答案
这似乎是对PLINQ工作:
This seems like a job for PLINQ:
return source.AsParallel().Select(s => ExecuteOrDownloadSomething(s));
此将并行使用线程的数量有限,只要它完成每个结果返回执行委托
This will execute the delegate in parallel using a limited number of threads, returning each result as soon as it completes.
如果在 ExecuteOrDownloadSomething()
方法IO的限制(例如,它实际上是下载的东西),你不想浪费线程,然后使用异步
- 等待
可能是有意义的,但它会更复杂
If the ExecuteOrDownloadSomething()
method is IO-bound (e.g. it actually downloads something) and you don't want to waste threads, then using async
-await
might make sense, but it would be more complicated.
如果你想充分利用的异步
,你不应该返回的IEnumerable
,因为它是同步的(也就是说,它阻止如果没有项目可用)。你需要的是某种形式的异步集合,你可以使用 ISourceBlock
(具体的 TransformBlock
)由TPL数据流为:
If you want to fully take advantage of async
, you shouldn't return IEnumerable
, because it's synchronous (i.e. it blocks if no items are available). What you need is some sort of asynchronous collection, and you can use ISourceBlock
(specifically, TransformBlock
) from TPL Dataflow for that:
ISourceBlock<TDst> Foo<TSrc, TDest>(IEnumerable<TSrc> source)
{
var block = new TransformBlock<TSrc, TDest>(
async s => await ExecuteOrDownloadSomethingAsync(s),
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
});
foreach (var item in source)
block.Post(item);
block.Complete();
return block;
}
如果来源是慢(即要开始处理来自的结果美孚()
迭代前源
完成后),您可能需要移动的foreach
和完成()
打电话给一个单独的任务
。甚至更好的解决办法是让源
到 ISourceBlock&LT;台橡方式&gt;
太
If the source is "slow" (i.e. you want to start processing the results from Foo()
before iterating source
is completed), you might want to move the foreach
and Complete()
call to a separate Task
. Even better solution would be to make source
into a ISourceBlock<TSrc>
too.
这篇关于如何从并行任务产生在.NET 4.5的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!