使用調度者

  調度程序控制訂閱何時開始以及何時發佈通知。它由三個組件組成。它首先是一個數據結構。當計劃要完成的任務時,它們被放入調度器以基於優先級或其他標準進行排隊。它還提供了一個執行上下文,它表示在哪裏執行任務(例如,在線程池,當前線程或另一個應用程序域中)。最後,它有一個時鐘爲自己提供時間的概念(通過訪問調度器的Now屬性)。在特定調度程序上調度的任務將遵守僅由該時鐘表示的時間。
  調度器還引入了虛擬時間的概念(由VirtualScheduler類型表示),其與在我們的日常生活中使用的實際時間不相關。例如,指定要花費100年時間完成的序列可以安排在僅僅5分鐘內在虛擬時間內完成。這將在測試和調試可觀察序列主題中介紹。

調度程序類型

  Rx提供的各種調度器類型都實現了IScheduler接口。可以通過使用Scheduler類型的靜態屬性來創建和返回這些對象。 ImmediateScheduler(通過訪問靜態Immediate屬性)將立即開始指定的操作。 CurrentThreadScheduler(通過訪問靜態CurrentThread屬性)將調度在執行原始調用的線程上執行的操作。操作不會立即執行,而是放在隊列中,並且只在當前操作完成後執行。 DispatcherScheduler(通過訪問靜態Dispatcher屬性)將調度對當前調度程序的操作,這對使用Rx的Silverlight開發人員有利。然後將指定的操作委派給Silverlight中的Dispatcher.BeginInvoke()方法。 NewThreadScheduler(通過訪問靜態NewThread屬性)在新線程上調度操作,並且是調度長時間運行或阻塞操作的最佳選擇。 TaskPoolScheduler(通過訪問靜態TaskPool屬性)在特定任務工廠調度操作。 ThreadPoolScheduler(通過訪問靜態ThreadPool屬性)調度線程池上的操作。兩個池調度程序都針對短時運行操作進行了優化。

使用計劃程序

  您可能已經在Rx代碼中使用了調度程序,而沒有明確說明要使用的調度程序的類型。這是因爲所有處理併發的Observable操作符都有多個重載。如果不使用將調度程序作爲參數的重載,Rx將使用最小併發性原則選擇一個默認調度程序。這意味着選擇引入滿足運營商需求的最少併發性的調度器。例如,對於返回具有有限和少量消息的observable的運算符,Rx調用Immediate。對於返回潛在大或無限數量的消息的操作符,調用CurrentThread。對於使用定時器的操作符,使用ThreadPool。
  因爲Rx使用最小併發性調度程序,如果您想爲性能目的引入併發性,或者遇到線程相關性問題,則可以選擇不同的調度程序。前者的一個例子是,當你不想阻塞一個特定的線程,在這種情況下,你應該使用ThreadPool。後者的一個示例是,當您想要在UI上運行計時器時,在這種情況下,您應該使用Dispatcher。要指定特定的調度器,可以使用那些接受調度器的運算符重載,例如Timer(TimeSpan.FromSeconds(10),Scheduler.DispatcherScheduler())。
  在以下示例中,源可觀察序列以瘋狂的速度生成值。 Timer運算符的默認重載將在ThreadPool上放置OnNext消息。

Observable.Timer(Timespan.FromSeconds(0.01))
          .Subscribe(…);

  這將在觀察者上快速排隊。我們可以通過使用ObserveOn運算符來改進此代碼,這允許您指定要用於將推送通知(OnNext)發送給觀察者的上下文。默認情況下,ObserveOn運算符確保OnNext將在當前線程上調用盡可能多的次數。您可以使用其重載並將OnNext輸出重定向到不同的上下文。此外,您可以使用SubscribeOn運算符返回將操作委派給特定調度程序的代理observable。例如,對於UI密集型應用程序,您可以委派所有後臺操作在後臺運行的調度程序上使用SubscribeOn並傳遞給它一個ThreadPoolScheduler。爲了接收被推出並且訪問任何UI元素的通知,您可以將DispatcherScheduler的實例傳遞給ObserveOn運算符。
  以下示例將在當前調度程序上計劃任何OnNext通知,以便在UI線程上發送任何推出的值。這對使用Rx的Silverlight開發人員特別有利。

Observable.Timer(Timespan.FromSeconds(0.01))
          .ObserveOn(Scheduler.DispatcherScheduler)
          .Subscribe(…);

  而不是使用ObserveOn運算符來更改observable序列生成消息的執行上下文,我們可以在正確的位置創建併發開始。 當運算符通過提供調度程序參數重載來參數化併發性引入時,傳遞合適的調度程序將導致使用ObserveOn運算符的位置減少。 例如,我們可以通過更改源使用的調度器來解除阻塞觀察者並直接訂閱UI線程,如下面的示例所示。 在這段代碼中,通過使用Timer重載,它需要一個調度器,並提供Scheduler.Dispatcher實例,從這個可觀察序列推出的所有值都將來自UI線程。

  
Observable.Timer(Timespan.FromSeconds(0.01), Scheduler.DispatcherScheduler)
          .Subscribe(…);

  您還應該注意,通過使用ObserveOn運算符,將爲通過原始可觀察序列的每個消息計劃一個操作。 這可能改變定時信息以及對系統施加額外的壓力。 如果你有一個查詢,組成在許多不同的執行上下文運行的各種可觀察序列,並且在查詢中進行過濾,最好在查詢中稍後放置ObserveOn。 這是因爲查詢可能會過濾掉大量消息,並且將ObserveOn運算符放在查詢中較早的位置會對將被過濾掉的消息執行額外的工作。 在查詢結束時調用ObserveOn運算符將產生最小的性能影響。
  明確指定調度程序類型的另一個優點是,您可以爲性能目的引入併發性,如以下代碼所示。

seq.GroupBy(...)
        .Select(x=>x.ObserveOn(Scheduler.NewThread))
        .Select(x=>expensive(x))  // perform operations that are expensive on resources
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章