我是Rx的新手。我可以看到使用熱觀測量的一些實實在在的好處,但是我最近問的差異是一個寒冷的觀察到的,等效枚舉之間是什麼(請參見下面的代碼片段)的問題...RX中可觀察到的冷態和正常的區別
var resRx = Observable.Range(1, 10);
var resOb = Enumerable.Range(1, 10);
誰能解釋很簡單,兩者之間的區別是什麼,以及從冷觀察者和可枚舉者中獲得的好處。
我是Rx的新手。我可以看到使用熱觀測量的一些實實在在的好處,但是我最近問的差異是一個寒冷的觀察到的,等效枚舉之間是什麼(請參見下面的代碼片段)的問題...RX中可觀察到的冷態和正常的區別
var resRx = Observable.Range(1, 10);
var resOb = Enumerable.Range(1, 10);
誰能解釋很簡單,兩者之間的區別是什麼,以及從冷觀察者和可枚舉者中獲得的好處。
這兩者之間有幾個區別。
誰控制了「枚舉」
隨着觀察到的(熱或冷),它是可觀察的,確定什麼的線程返回的值時,和。另一方面,enumerable在請求它時獲取每個值,並在請求枚舉的線程上處理。
代碼流
處理可枚舉在一個典型的做法對於每個循環(或偶爾獲得枚舉和使用而循環)。在繼續之前,您的代碼通常會處理所有值。觀察對象需要回調。阻止你的代碼的進一步執行(比如說不要退出控制檯應用程序)需要額外的代碼。有些觀察對象的阻塞操作符,如First
,但它們是例外情況,而不是正常使用的規則。
以這個簡單的示例程序爲例。使用枚舉值,在繼續下一部分之前,所有的值都被寫入。但是,可觀察值的值不能保證永遠不會被寫入。在程序終止之前寫入多少值幾乎是一個競爭條件。
static void Main(string[] args)
{
var xs = Enumerable.Range(1, 10);
foreach (var x in xs)
{
Console.WriteLine(x);
}
//at this point, all values have been written
var ys = Observable.Range(1, 10);
ys.Subscribe(y => Console.WriteLine(y));
//at this point, no values have been written (in general)
//either add a Console.ReadKey or some sort of wait handle that
//is set in the OnCompleted of the observer to get values
}
異步進程
就像你必須編寫額外的代碼來阻止和等待觀察的,編寫使用異步進程一個IEnumerable需要一些額外的工作。這就是兩者之間真正的區別。
例如,在我目前正在處理的應用程序中,我需要搜索可能連接到串行端口的設備。 IObservable非常適合這種情況,因爲它允許我進行回調,並在每次找到設備時通知應用程序,而無需阻止以及何時完成操作。這個可觀察的資格被視爲冷可觀察,因爲它不會推出數據,除非有訂戶,並且每個訂閱都會獲得所有結果。 (與典型的冷觀察不同,我在訂閱之前開始工作,但沒有數據丟失,因爲它被緩衝到重播主題中。)但是,由於異步將其轉換爲Enumerable並不合理性質。
幾乎所有你習慣了的「Enumerables」都是「冷」Enumerables?爲什麼?因爲如果您要兩次對Enumerable.Range進行ForEach,就會得到兩倍的數字。
如果Enumerable.Range是一個Hot Enumerable,它只會給你一個列表,而第二個ForEach只會是空的。
對於Rx,Cold Observable意味着每次調用Subscribe(相當於Rx中的ForEach)時,都會收到一個新的東西列表。像FromEvent這樣的熱點觀察者不會在每次訂閱時給你一個新的事件流,它只是另一個連接到同一事件流的連接。
雖然Rx的優勢是什麼?能夠將該範圍轉換爲異步請求:
IObservable<Image> fetchImageByIndex(int imageIndexOnSite);
Observable.Range(0, 10)
.SelectMany(x => fetchImageByIndex(x))
.Subscribe(image => saveImageToDisk(image));
感謝Gideon ...偉大的洞察力。 –