2010-08-31 49 views
1

什麼將是實現具有關鍵任務是進行如下操作的最佳方法: - )實施「只是一個」和「不平行」與任務並行庫語義

選項1只有這一個密鑰有待處理。例如,可以使用ASP.NET MVC來爲縮略圖圖像排隊單個渲染,而不管圖像Url被擊中多少次。只有一個運行,所有其他請求等待完成。

選項2)所有具有相同密鑰的項目必須按順序執行。可用於例如確保將文件從後備存儲獲取到本地緩存的操作不會同時嘗試將文件轉移到緩存。選項1是這種情況的一個特例,其中使用同一個鍵的後續操作只是被丟棄(通常只保存文件存在檢查)。

我有一個現有的WorkQueue處理這兩種情況(以及Apartment狀態,ThreadPriority設置和最大並行度)。 TPL似乎是取代這一點的最佳解決方案,並將帶來更好的取消選項。

具有延續性的嵌套任務看起來很有希望,但維護當前隊列任務的字典很快就會在TaskFactory和TaskScheduler類之間變得雜亂無章。從Task繼承也是有問題的,因爲TaskFactory和TaskScheduler在Task上都是通用的。

大多數任務並行示例假定該任務集是事先知道的。在這種情況下,新任務會一直添加,需要根據請求的操作和傳入的密鑰將其丟棄或鏈接到現有任務。

是否有人使用TPL實現了與此類似的任何操作?如果是這樣,你有沒有參加你的Task,TaskScheduler和TaskFactory類?

+0

錯讀你的問題,oops – 2010-08-31 23:15:00

回答

1

也許,我能想到的一個方法是

  1. 創建一個包裝類 - 說KeyProcessor排隊一個關鍵項目。
  2. KeyProcessor.Run()方法將能夠處理任何您需要的排隊語義。從本質上講,它會尋找任何待處理工作的內部隊列,然後繼續按順序進行。
  3. 維護KeyProcessor對象的字典。
  4. 對於任何新任務,請在字典中檢查相同的密鑰。如果不存在,則添加它。在其上排隊任務。如果它沒有運行,那麼使用Run方法作爲動作,使用TPL進行安排。
  5. 使用ContinueWith來安排維護者任務 - 例如,只要任務執行KeyProcessor.Run完成,延續任務就可以檢查是否有更多任務被安排在同一個密鑰上(因爲它已經完成)並且再次啓動它或者刪除從字典。

以上所有內容對於線程同步點來說都會非常棘手,而不是存在於System.Collections.Concurrent命名空間中的少數有趣集合。這將使上述邏輯更加簡單。例如,ConcurrentDictionary.GetOrAdd將允許以線程安全的方式查找和/或添加KeyProcessor對象。

+0

使用Continuations的自定義任務工廠能夠解決這個問題。博客文章在這裏:http://blog.abodit.com/2010/09/constrained-parallelism-for-the-task-parallel-library/。由於你的建議很接近,我會給你答案分數。 – 2010-11-15 03:14:52

1

此問題與我在ReactiveXaml中解決的問題類似,雖然我也記錄了以前的請求。看看QueuedAsyncMRUCache(及其blog entry)的代碼 - 這段代碼結合了TPL和Reactive Extensions來完成這種事情,但它確保了對同一個密鑰的第二次請求將在第一個而不是發出另一個請求。

+1

謝謝,有趣,但不是我所需要的。我應該補充一點,我希望能夠在任何已添加的任務中進行「開火併忘記」以及開火和等待。我還希望一旦最後一個執行完畢就將鍵移除。例如更新網站上用戶的上次訪問時間:五次同時點擊會摺疊爲一次寫入,但稍後會記錄一次。 – 2010-09-01 00:57:31

+0

也許至少你可以從我實施它的方式得到一些啓發 – 2010-09-01 03:27:30

+0

有趣的是,我最終實現了你爲項目選項#2指定的主要內容:https://gist.github.com/2877c8181d5ae4c8ac02 – 2011-11-23 01:14:11