[英]Subscribing to observable sequence with async function
我有一個asnyc
函數,我想在IObservable
序列中的每個觀察時調用,一次限制傳遞到一個事件。 消費者希望飛行中不超過一條消息; 如果我理解正確的話,這也是RX合約。
考慮這個樣本:
static void Main() {
var ob = Observable.Interval(TimeSpan.FromMilliseconds(100));
//var d = ob.Subscribe(async x => await Consume(x)); // Does not rate-limit.
var d = ob.Subscribe(x => Consume(x).Wait());
Thread.Sleep(10000);
d.Dispose();
}
static async Task<Unit> Consume(long count) {
Console.WriteLine($"Consuming {count} on thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(750);
Console.WriteLine($"Returning on thread {Thread.CurrentThread.ManagedThreadId}");
return Unit.Default;
}
Consume
函數偽造750 ms處理時間, ob
每100 ms產生一次事件。 上面的代碼有效,但在隨機線程上調用task.Wait()
。 如果我改為在注釋掉的第3行中訂閱, Consume
與ob
生成事件相同的速率調用Consume
(我甚至無法理解我在這個注釋語句中使用的Subscribe
重載,所以它可能是無意義的)。
那么如何從可觀察序列到async
函數一次正確地傳遞一個事件呢?
訂閱者不應該長時間運行,因此不支持在Subscribe處理程序中執行長時間運行的異步方法。
相反,請將您的異步方法視為單個值可觀察序列,該序列從另一個序列中獲取值。 現在你可以編寫序列,這就是Rx的設計目的。
現在你已經實現了這個飛躍,你可能會有類似@Reijher在Howto中從rx subscribe回調異步函數的東西? 。
他的代碼細分如下。
//The input sequence. Produces values potentially quicker than consumer
Observable.Interval(TimeSpan.FromSeconds(1))
//Project the event you receive, into the result of the async method
.Select(l => Observable.FromAsync(() => asyncMethod(l)))
//Ensure that the results are serialized
.Concat()
//do what you will here with the results of the async method calls
.Subscribe();
在此方案中,您將創建隱式隊列。 在生產者比消費者更快的任何問題中,需要使用隊列在等待時收集值。 我個人更喜歡通過將數據放入隊列來使其顯式化。 或者,您可以明確地使用調度程序來發出信號,表明該應該是松弛的線程模型。
對於Rx新手來說,這似乎是一個流行的障礙(在訂閱處理程序中執行異步)。 有很多原因導致指導不是將它們放在您的訂戶中,例如:1。您打破了錯誤模型2.您正在混合異步模型(rx在這里,任務那里)3。訂閱是組合的消費者異步序列。 異步方法只是一個單獨的值序列,因此該視圖不能是序列的結尾,但結果可能是。
UPDATE
為了說明關於打破錯誤模型的評論,這是OP樣本的更新。
void Main()
{
var ob = Observable.Interval(TimeSpan.FromMilliseconds(100));
var d = ob.Subscribe(
x => ConsumeThrows(x).Wait(),
ex=> Console.WriteLine("I will not get hit"));
Thread.Sleep(10000);
d.Dispose();
}
static async Task<Unit> ConsumeThrows(long count)
{
return await Task.FromException<Unit>(new Exception("some failure"));
//this will have the same effect of bringing down the application.
//throw new Exception("some failure");
}
在這里我們可以看到,如果要拋出OnNext
處理程序,那么我們就不受Rx OnError
處理程序的保護。 該異常將無法處理,很可能會導致應用程序失效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.