当我使用阻塞代码Task.Wait()
时,我正在遇到死锁,等待一个async
方法在里面等待Rx LINQ查询。
这是一个例子:
public void BlockingCode()
{
this.ExecuteAsync().Wait();
}
public async Task ExecuteAsync()
{
await this.service.GetFooAsync().ConfigureAwait(false);
//This is the RX query that doesn't support ConfigureAwaitawait
await this.service.Receiver
.FirstOrDefaultAsync(x => x == "foo")
.Timeout(TimeSpan.FromSeconds(1));
}
所以,我的问题是,在等待的IObservable上是否有任何等效的ConfigureAwait,以确保不会在同一SynchronizationContext
上恢复延续。
答案 0 :(得分:4)
你必须理解等待一个Observable"手段。查看this。所以,在语义上,你的代码
await this.service.Receiver
.FirstOrDefaultAsync(x => x == "foo")
.Timeout(TimeSpan.FromSeconds(1));
相当于
await this.service.Receiver
.FirstOrDefaultAsync(x => x == "foo")
.Timeout(TimeSpan.FromSeconds(1))
.LastAsync()
.ToTask();
(请注意,这里有一些冗余,调用FirstOrDefaultAsync
和LastAsync
,但这没问题。)
所以你得到了你的任务(如果可以的话,可能需要额外的CancellationToken
)。您现在可以使用ConfigureAwait
。
答案 1 :(得分:2)
ConfigureAwait
与awaiters本身没有直接关系,而是TPL的一项功能,用于配置Task
应该如何完成。这是有问题的,因为这个TPL方法不会返回一个新的Task
,所以你不能通过转换为一个observable来组合它。
Rx本身基本上是自由线程的。您可以使用比Tasks
更精细的控制来控制订阅和事件期间使用的线程 - 有关详细信息,请参阅此处:ObserveOn and SubscribeOn - where the work is being done
很难修复你的代码,因为你没有提供一个小但完整的工作示例 - 但是,Rx中的内置函数不会尝试编组到特定的线程,除非你明确指示他们之一上述运营商。
如果您合并Observable.FromAsync
之类的运算符将Task
转换为可观察对象,则可以使用Observable.SubscribeOn(Scheduler.Default)
从当前Task
开始SynchronizationContext
这里有一个要点(为LINQPad设计,使用nuget包rx-main运行):https://gist.github.com/james-world/82c3cc39babab7870f6d