在我的C#应用​​程序中结合使用Task和IObservable是不好的做法?

Seb*_*eth 3 c# task-parallel-library system.reactive

我最近进入了Rx,我正在使用它来帮助我从数据挖掘应用程序中的几个API中提取数据.

我有一个为每个API实现的接口,它封装了对每个API的公共调用,例如

public interface IMyApi {

    IObservable<string> GetApiName(); //Cold feed for getting the API's name.

    IObservable<int> GetNumberFeed(); //Hot feed of numbers from the API

}
Run Code Online (Sandbox Code Playgroud)

我的问题是关于冷IObservables vs Tasks.在我看来,冷可观察基本上是一项任务,它们的运作方式大致相同.当你可以争辩说任务就是你所需要的时候,把一个任务"抽象"为一个冷酷的观察者,这让我感到很奇怪.同时使用cold observable来包装Tasks会隐藏活动的性质,因为签名看起来与热的observable相同.

我可以代表上述界面的另一种方式是:

public interface IMyApi {

    Task<string> GetApiNameAsync(); //Async method for getting the API's name.

    IObservable<int> GetNumberFeed(); //Hot feed of numbers from the API

}
Run Code Online (Sandbox Code Playgroud)

对于为什么我不应该在Tasks和IObservable之间混合和匹配,有一些传统的智慧吗?

编辑:澄清 - 我已经阅读了其他发布的讨论并理解了Rx和TPL之间的关系,但我的担忧主要在于将两者结合在一个应用程序中是否安全,以及它是否会导致不良做法或线程化和调度陷阱?

Ana*_*tts 5

我的问题是关于冷IObservables vs Tasks.在我看来,冷可观察基本上是一项任务,它们的运作方式大致相同

重要的是要注意事实并非如此,它们是非常不同的.这是核心差异:

// Nothing happens here at all! Just like calling Enumerable.Range(0, 100000000)
// doesn't actually create a huge array, until I use foreach.
var myColdObservable = MakeANetworkRequestObservable();

// Two network requests made!
myColdObservable.Subscribe(x => /*...*/);
myColdObservable.Subscribe(x => /*...*/);

// Only ***one*** network request made, subscribers share the
// result
var myTaskObservable = MakeATask().ToObservable();
myTaskObservable.Subscribe(x => /*...*/);
myTaskObservable.Subscribe(x => /*...*/);
Run Code Online (Sandbox Code Playgroud)

为什么这很重要?Rx中的几个方法Retry依赖于这种行为:

// Retries three times, then gives up
myColdObservable.Retry(3).Subscribe(x => /*...*/);

// Actually *never* retries, and is effectively the same as if the
// Retry were never there, since all three tries will get the same
// result!
myTaskObservable.Retry(3).Subscribe(x => /*...*/);
Run Code Online (Sandbox Code Playgroud)

所以一般来说,让你的Observables 变冷会让你的生活更轻松.

我怎么能让任务冷?

使用Defer运算符:

var obs = Observable.Defer(() => CreateATask().ToObservable());

// CreateATask called *twice* here
obs.Subscribe(/*...*/);
obs.Subscribe(/*...*/);
Run Code Online (Sandbox Code Playgroud)