[英]Observable.Interval with select to stateful service causes strange behaviour
我試圖使用Observable.Interval結合select來輪詢服務,這似乎是一種語法上很好的方法。 但是每當我嘗試實現一種等待observable完成的方法時,我會得到奇怪的行為,其中select多次調用的服務被調用。
沒有等待,我得到了正在尋找的正確行為......
碼
private static ConcurrentQueue<string> _data = new ConcurrentQueue<string>(new [] { "a", "b", "c", "d" });
static void Main(string[] args)
{
var observable = Observable
.Interval(TimeSpan.FromSeconds(2))
.Select(Transform)
.TakeWhile(x => x != null);
Console.WriteLine("Starting subcription");
var disposable = observable.Subscribe(x => Console.WriteLine("Event raised for {0}", x));
Console.WriteLine("Waiting for subcription to complete");
// need to wait here
Console.WriteLine("Press any key to exit. . .");
Console.ReadKey();
}
private static string Transform(long x)
{
string result;
_data.TryDequeue(out result);
Console.WriteLine("Transform invoked [x: {0}, Result: {1}]", x, result ?? "NULL");
return result;
}
產量
Starting subcription
Waiting for subcription to complete
Press any key to exit. . .
Transform invoked [x: 0, Result: a]
Event raised for a
Transform invoked [x: 1, Result: b]
Event raised for b
Transform invoked [x: 2, Result: c]
Event raised for c
Transform invoked [x: 3, Result: d]
Event raised for d
Transform invoked [x: 4, Result: NULL]
如果我在observable上調用擴展方法wait,它似乎會導致每個間隔調用兩次Transform,並且只有一個值返回給事件...
碼
private static ConcurrentQueue<string> _data = new ConcurrentQueue<string>(new [] { "a", "b", "c", "d" });
static void Main(string[] args)
{
var observable = Observable
.Interval(TimeSpan.FromSeconds(2))
.Select(Transform)
.TakeWhile(x => x != null);
Console.WriteLine("Starting subcription");
var disposable = observable.Subscribe(x => Console.WriteLine("Event raised for {0}", x));
Console.WriteLine("Waiting for subcription to complete");
observable.Wait();
Console.WriteLine("Press any key to exit. . .");
Console.ReadKey();
}
private static string Transform(long x)
{
string result;
_data.TryDequeue(out result);
Console.WriteLine("Transform invoked [x: {0}, Result: {1}]", x, result ?? "NULL");
return result;
}
產量
Starting subcription
Waiting for subcription to complete
Transform invoked [x: 0, Result: a]
Event raised for a
Transform invoked [x: 0, Result: b]
Transform invoked [x: 1, Result: c]
Event raised for c
Transform invoked [x: 1, Result: d]
Transform invoked [x: 2, Result: NULL]
Transform invoked [x: 2, Result: NULL]
Press any key to exit. . .
我懷疑這是因為Wait在幕后創建了第二個訂閱,我的observable后面的服務是有狀態的。
我見過人們建議使用ToTask來等待一個observable完成,這有着同樣奇怪的行為。
那么,在所有訂閱者接收相同數據集的同時,在觀察者后面輪詢有狀態服務的正確方法是什么?
幾件事:
Subscribe
期間更改狀態,而不是Select
其他運算符。 我不確定這對你的例子是否實用。 Select
運算符等。您有兩個訂閱,一個來自Subscribe
,另一個來自Wait
,所以你' ll有兩個定時器,兩個Select
運算符附加調用Transform
。 您可以通過以下兩種方式之一解決此問題:
您作為熱點可觀測量的可觀察量將如下所示:
var observable = Observable
.Interval(TimeSpan.FromSeconds(2))
.Select(Transform)
.TakeWhile(x => x != null)
.Publish()
.RefCount();
我的建議是,既然你在你的observable中改變了狀態,我會很熱,以確保你最終沒有運行兩次。
確保您只訂閱了一次observable。 省略對Subscribe
的第一次調用,然后將調用留給Wait
。 如果您仍想發出一些日志消息(正如您在訂閱中所做的那樣),請添加一個Do
-step:
private static ConcurrentQueue<string> _data = new ConcurrentQueue<string>(new [] { "a", "b", "c", "d" });
static void Main(string[] args)
{
var observable = Observable
.Interval(TimeSpan.FromSeconds(2))
.Select(Transform)
.TakeWhile(x => x != null);
Console.WriteLine("Wait for the observable to complete.");
observable
.Do(x => Console.WriteLine("Event raised for {0}", x))
.Wait();
Console.WriteLine("Press any key to exit. . .");
Console.ReadKey();
}
private static string Transform(long x)
{
string result;
_data.TryDequeue(out result);
Console.WriteLine("Transform invoked [x: {0}, Result: {1}]", x, result ?? "NULL");
return result;
}
請注意, Wait
將阻塞(這在Main
方法中是不可避免的)。 此外,當您的observable為空時它會拋出。 如果您對observable的任何值不感興趣,請添加LastOrDefault
-step。
等待observable是一種固有的異步操作,所以你應該檢查是否可以使用ToTask
而不是Wait
並在異步方法中等待它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.