Observable.FromAsync vs Task.ToObservable

Есть ли у кого-нибудь руководство, когда использовать один из этих методов над другим. Они, похоже, делают то же самое, что и конвертируют из TPL Task в Observable.

Observable.FromAsync, похоже, поддерживают маркеры отмены, которые могут быть тонкой разницей, которая позволяет методу, генерирующему задачу, участвовать в совместной аннулировании, если обнаружено наблюдаемое.

Просто интересно, не хватает ли я чего-то очевидного в том, почему вы используете один над другим.

Спасибо

Ответ 1

Глядя на код, кажется, что (по крайней мере, в некоторых потоках), который Observable.FromAsync вызывает в .ToObservable() *. Я уверен, что намерение состоит в том, что они должны быть семантически эквивалентными (при условии, что вы передаете одни и те же параметры, например, Scheduler, CancellationToken и т.д.).

Один лучше подходит для цепочки/беглого синтаксиса, может лучше читать изолированно. Какой бы стиль кодирования вы ни предпочитали.

*https://github.com/Reactive-Extensions/Rx.NET/blob/859e6159cb07be67fd36b18c2ae2b9a62979cb6d/Rx.NET/Source/System.Reactive.Linq/Reactive/Linq/QueryLanguage.Async.cs#L727

Ответ 2

Observable.FromAsync принимает TaskFactory в форме Func<Task> или Func<Task<TResult>>, в этом случае задача создается и выполняется только тогда, когда подписывается наблюдаемый.

Где в качестве .ToObservable() требуется уже созданная (и таким образом запущенная) задача.

Ответ 3

@Sickboy ответ правильный.

  • Observable.FromAsync() запустит задачу в момент подписки.
  • Task.ToObservable() нужна уже запущенная задача.

Одним из вариантов использования Observable.FromAsync является управление повторным входом для нескольких вызовов асинхронного метода.

Это пример, где эти два метода не эквивалентны:

//ob is some IObservable<T>

//ExecuteQueryAsync is some async method
//Here, ExecuteQueryAsync will run **serially**, the second call will start
//only when the first one is already finished. This is an important property
//if ExecuteQueryAsync does not support reentrancy
ob
.Select(x => Observable.FromAsync(() => ExecuteQueryAsync(x))
.Concat()
.ObserveOnDispatcher()
.Subscribe(action)

против

//ob is some IObservable<T>

//ExecuteQueryAsync is some async method
//Even when the 'Subscribe' action order will be the same as the first 
//example because of the 'Concat', ExecuteQueryAsync calls could be     
//parallel, the second call to the method could start before the end of the 
//first call. 
.Select(x => ExecuteQueryAsync(x).ToObservable())
.Concat()
.Subscribe(action)

Обратите внимание, что в первом примере может потребоваться метод ObserveOn() или ObserveOnDispatcher(), чтобы гарантировать, что action выполняется на исходном диспетчере, поскольку Observable.FromAsync не ожидает задачи, таким образом, продолжение выполнено на любом доступном диспетчере

Ответ 4

Помимо возможности использования CancellationToken, FromAsync завершает работу, поэтому это позволяет изменять логику задачи на основе условий во время подписки. Обратите внимание, что Задача не будет запущена, внутренняя задача. Будет вызван ToObservable. Func действительно позволяет вам запускать задачу, хотя при ее создании.