[英]How to Subscribe with async method in Rx?
I have following code:我有以下代码:
IObservable<Data> _source;
...
_source.Subscribe(StoreToDatabase);
private async Task StoreToDatabase(Data data) {
await dbstuff(data);
}
However, this does not compile.但是,这不会编译。 Is there any way how to observe data asynchronously?
有没有办法异步观察数据? I tried
async void
, it works, but I feel that given solution is not feasible.我尝试了
async void
,它有效,但我觉得给定的解决方案不可行。
I also checked Reactive Extensions Subscribe calling await , but it does not answer my question (I do not care about the SelectMany
result.)我还检查了Reactive Extensions Subscribe 调用 await ,但它没有回答我的问题(我不关心
SelectMany
结果。)
You don't have to care about the SelectMany
result.您不必关心
SelectMany
结果。 The answer is still the same... though you need your task to have a return type (ie Task<T>
, not Task
).答案仍然相同......尽管您需要您的任务具有返回类型(即
Task<T>
,而不是Task
)。
Unit
is essentially equivalent to void
, so you can use that: Unit
本质上等同于void
,因此您可以使用它:
_source.SelectMany(StoreToDatabase).Subscribe();
private async Task<Unit> StoreToDatabase(Data data)
{
await dbstuff(data);
return Unit.Default;
}
This SelectMany
overload accepts a Func<TSource, Task<TResult>
meaning the resulting sequence will not complete until the task is completed.此
SelectMany
重载接受Func<TSource, Task<TResult>
意味着结果序列在任务完成之前不会完成。
Late answer, but I think that the following extension methods correctly encapsulate what Charles Mager proposed in his answer :迟到的答案,但我认为以下扩展方法正确地封装了 Charles Mager 在他的回答中提出的内容:
public static IDisposable SubscribeAsync<T>(this IObservable<T> source,
Func<Task> asyncAction, Action<Exception> handler = null)
{
Func<T,Task<Unit>> wrapped = async t =>
{
await asyncAction();
return Unit.Default;
};
if(handler == null)
return source.SelectMany(wrapped).Subscribe(_ => { });
else
return source.SelectMany(wrapped).Subscribe(_ => { }, handler);
}
public static IDisposable SubscribeAsync<T>(this IObservable<T> source,
Func<T,Task> asyncAction, Action<Exception> handler = null)
{
Func<T, Task<Unit>> wrapped = async t =>
{
await asyncAction(t);
return Unit.Default;
};
if(handler == null)
return source.SelectMany(wrapped).Subscribe(_ => { });
else
return source.SelectMany(wrapped).Subscribe(_ => { }, handler);
}
I've been using TPL DataFlow to control back pressure and have used it to solve this problem.我一直在使用TPL DataFlow来控制背压,并用它来解决这个问题。
The key part is ITargetBlock<TInput>.AsObserver()
- source .关键部分是
ITargetBlock<TInput>.AsObserver()
- source 。
// Set a block to handle each element
ITargetBlock<long> targetBlock = new ActionBlock<long>(async p =>
{
Console.WriteLine($"Received {p}");
await Task.Delay(1000);
Console.WriteLine($"Finished handling {p}");
},
new ExecutionDataflowBlockOptions { BoundedCapacity = 1 });
// Generate an item each second for 10 seconds
var sequence = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10);
// Subscribe with an observer created from the target block.
sequence.Subscribe(targetBlock.AsObserver());
// Await completion of the block
await targetBlock.Completion;
The important part here is that the ActionBlock's bounded capacity is set to 1. This prevents the block from receiving more than one item at a time and will block OnNext if an item is already being processed!这里的重要部分是 ActionBlock 的有界容量设置为 1。这可以防止块一次接收多个项目,如果项目已经在处理, 则会阻止 OnNext !
My big surprise here was that it can be safe to call Task.Wait
and Task.Result
inside your subscription.我最大的惊喜是在订阅中调用
Task.Wait
和Task.Result
是安全的。 Obviously, if you have called ObserverOnDispatcher()
or similar you will probably hit deadlocks.显然,如果您调用了
ObserverOnDispatcher()
或类似方法,您可能会陷入僵局。 Be careful!小心!
So you want to run the Store Data Procedure, possibly some other procedure and asynchronously await the completion or partial result.所以你想运行存储数据过程,可能是其他一些过程,并异步等待完成或部分结果。 How about Create constructor shown here:
此处显示的创建构造函数如何:
IObservable<Int32> NotifyOfStoringProgress =
Observable.Create(
(Func<IObserver<Int32>, Task>)
(async (ObserverToFeed) =>
{
ObserverToFeed.OnNext(-1);
Task StoreToDataBase = Task.Run(()=> {;});
ObserverToFeed.OnNext(0);
;;
await StoreToDataBase;
ObserverToFeed.OnNext(1);
;;
}));
NotifyOfStoringProgress.Subscribe(onNext: Notification => {;});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.