TPL Dataflow和Rx组合示例

时间:2012-07-08 14:41:18

标签: .net task-parallel-library system.reactive c#-5.0 tpl-dataflow

我只是想学习它们以及如何一起使用它们。我知道他们可以相互补充,我找不到实际做某事的例子。

1 个答案:

答案 0 :(得分:20)

让我先从一些背景开始。

.NET框架有许多特殊类型 - 适当的类或接口 - Task<T>IObservable<T>Nullable<T>IEnumerable<T>Lazy<T>,等 - 为基础类型T提供特殊权力。

TPL使用Task<T>来表示单个值T的异步计算。

Rx使用IObservable<T>来表示T的零个或多个值的异步计算。

这两者的“异步计算”方面将TPL和Rx结合在一起。

现在,TPL也使用类型Task来表示Action lambda的异步执行,但这可以被认为是Task<T>的特殊情况Tvoid。非常像c#中的标准方法返回void,如下所示:

public void MyMethod() { }

Rx也允许使用名为Unit的特殊类型的相同特殊情况。

TPL和Rx之间的差异在于返回的值的数量。 TPL是唯一的,而Rx是零或更多。

因此,如果您通过仅使用返回单个值的可观察序列来以特殊方式处理Rx,则可以采用与TPL类似的方式进行一些计算。

例如,在TPL中我可以写:

Task.Factory
    .StartNew(() => "Hello")
    .ContinueWith(t => Console.WriteLine(t.Result));

在Rx中,等价物是:

Observable
    .Start(() => "Hello")
    .Subscribe(x => Console.WriteLine(x));

我可以在Rx中更进一步,指定应该使用TPL来执行计算:

Observable
    .Start(() => "Hello", Scheduler.TaskPool)
    .Subscribe(x => Console.WriteLine(x));

(默认使用线程池。)

现在我可以做一些“混合和匹配”。如果我添加对System.Reactive.Threading.Tasks命名空间的引用,我可以很容易地在任务和可观察对象之间移动。

Task.Factory
    .StartNew(() => "Hello")
    .ToObservable()
    .Subscribe(x => Console.WriteLine(x));

Observable
    .Start(() => "Hello")
    .ToTask()
    .ContinueWith(t => Console.WriteLine(t.Result));

请注意ToObservable()&amp; .ToTask()调用并将结果从一个库转换到另一个库。

如果我有一个返回多个值的observable,我可以使用可观察的.ToArray()扩展方法将多个序列值转换为可以转换为任务的单个数组值。像这样:

Observable
    .Interval(TimeSpan.FromSeconds(1.0))
    .Take(5) // is IObservable<long>
    .ToArray()
    .ToTask() // is Task<long[]>
    .ContinueWith(t => Console.WriteLine(t.Result.Length));

我认为这是对你的问题的一个相当基本的答案。这是你期待的吗?