【发布时间】:2018-03-21 05:42:29
【问题描述】:
我有一个IObservable<T> 序列,其中T 是一个KeyValuePair<TKey, TValue>,我使用来自System.Reactive.Linq 的GroupBy 对其进行分组。
我想对每个 IGroupedObservable<TKey, KeyValuePair<TKey, TValue>> 执行聚合操作,但该聚合被定义为 Func<IEnumerable<TValue>, TValue>。
例如,在这里我想计算每个不同单词出现的次数并将其打印到控制台:
Func<IEnumerable<int>, int> aggregate = x => x.Count();
using (new[] { "one", "fish", "two", "fish" }
.Select(x => new KeyValuePair<string, int>(x, 1))
.ToObservable()
.GroupBy(x => x.Key)
.Select(x => new KeyValuePair<string, IEnumerable<int>>(
x.Key,
x.Select(y => y.Value).ToEnumerable()))
//.SubscribeOn(Scheduler.Default)
.Subscribe(x => Console.WriteLine($"{x.Key} [{aggregate(x.Value)}]")))
{
}
我希望输出与此类似(顺序不重要):
one [1]
fish [2]
two [1]
但相反,它要么阻塞(可能是死锁),要么根本不提供任何输出(当我取消注释 LINQ 语句的 SubscribeOn 子句时)。
我已尝试从实际使用场景中减少上述代码,该场景尝试链接两个 TPL Dataflow 块但遇到类似行为:
Func<IEnumerable<int>, int> aggregate = x => x.Sum();
var sourceBlock = new TransformBlock<string, KeyValuePair<string, int>>(x => new KeyValuePair<string, int>(x, 1));
var targetBlock = new ActionBlock<KeyValuePair<string, IEnumerable<int>>>(x => Console.WriteLine($"{x.Key} [{aggregate(x.Value)}]"));
using (sourceBlock.AsObservable()
.GroupBy(x => x.Key)
.Select(x => new KeyValuePair<string, IEnumerable<int>>(x.Key, x.Select(y => y.Value).ToEnumerable()))
.Subscribe(targetBlock.AsObserver()))
{
foreach (var kvp in new[] { "one", "fish", "two", "fish" })
{
sourceBlock.Post(kvp);
}
sourceBlock.Complete();
targetBlock.Completion.Wait();
}
我知道有框架提供了 Sum 和 Count 方法,可在 IObservable<T> 上运行,但我受限于 IEnumerable<T> 聚合函数。
我误解了ToEnumerable,我该怎么做才能解决它?
编辑:
IEnumerable<T> 的约束是由我试图链接的两个数据流块的 target 引入的,其签名不是我可以更改的。
【问题讨论】:
标签: c# linq system.reactive tpl-dataflow