ConfigureAwait for IObservable <t>

时间:2015-05-15 14:19:15

标签: c# asynchronous async-await system.reactive

当我使用阻塞代码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上恢复延续。

2 个答案:

答案 0 :(得分:4)

你必须理解等待一个Observable&#34;手段。查看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();

(请注意,这里有一些冗余,调用FirstOrDefaultAsyncLastAsync,但这没问题。)

所以你得到了你的任务(如果可以的话,可能需要额外的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