【发布时间】:2012-01-25 06:40:04
【问题描述】:
我有一些无限生成器方法,包括一些长时间运行和无限长时间运行的生成器。
IEnumerable<T> ExampleOne() {
while(true) // this one blocks for a few seconds at a time
yield return LongRunningFunction();
}
IEnumerable<T> ExampleTwo() {
while(true) //this one blocks for a really long time
yield return OtherLongRunningFunction();
}
我的目标是拥有一个无限序列,将两个示例中的项目组合在一起。这是我尝试过的,使用 PLINQ:
IEnumerable<T> combined = new[] { ExampleOne(), ExampleTwo() }
.AsParallel()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
.SelectMany(source => source.GetRequests());
这似乎恰当地将两个 IEnumerable 组合成一个新的,IEnumerable #1 和 #2 中的项目只要出现在两个源 IEnumerables 中的任何一个中都可用:
//assuming ExampleTwo yields TWO but happens roughly 5 times
//less often then ExampleOne
Example output: one one one one one TWO one one one one one one TWO
但是,似乎有时(通常在运行许多 小时 之后)OtherLongRunningFunction() 会运行很长时间而不会返回,并且在难以重现的条件下,@987654327 @sequence 将阻止它,而不是继续从第一个 LongRunningFunction 返回结果。看起来虽然组合并行查询开始使用两个线程,但它决定稍后切换到一个线程。
我的第一个想法是“这可能是 RX Observable.Merge 的工作,而不是 PLINQ。”但我会很感激这两个答案,它们显示了处理这种情况的正确替代方法,以及关于 PLINQ 如何在查询开始数小时后改变并行度的机制的解释。
【问题讨论】:
-
我不能说我对 PLINQ 有很多经验,所以这主要是不合格的猜测:看起来好像你假设结合
ExampleOne()和ExampleTwo()并运行AsParallel()on生成的IEnumerable将通过从第一个返回一个结果和从第二个返回一个结果来严格交替。难道这个假设是错误的?如果是这样,您最终可能会遇到正在处理的序列看起来像 1st 2nd 1st 2nd 1st 1st 1st 2nd 1st 2nd 1st 1st 2nd 1st 2nd 2nd 2nd 2nd... 这可以解释为什么它看起来好像你被困在第二个问题上。 -
@Nailuj 这实际上更像我所期望的 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 2 等,2s 是相当罕见的,并且可以有连续 2 秒之间的长时间。我希望组合序列继续返回 1,事实上,这实际上是大多数情况下发生的情况。但有时它也会停止返回 1。
-
另一个想法:可能是 PLINQ 以并行处理相同数量的 1 和 2 开始,但由于 1 完成得更快,它将显示为您描述的序列。但是,每当 1 完成时,该“点”将分别由 1 和 2 交替填充。结果是,一开始,看起来好像你得到了很多 1,只有很少的 2,但从长远来看,正在处理的任务的“队列”会被 2 填满,因此似乎卡住了?如果不完全像这样,它可能有点相关吗?只是想大声思考:-)
-
您是否真的验证过这种行为(在两个长时间运行的函数执行期间添加一些诊断日志记录,包括当前线程 ID)
标签: c# system.reactive plinq