2012-06-22 51 views
4

,我發現自己最近使用SemaphoreSlim類,限制在(大)的可並行操作的進度工作流資源:以流資源的並行操作的進度限制工作

// The below code is an example of the structure of the code, there are some 
// omissions around handling of tasks that do not run to completion that should be in production code 

SemaphoreSlim semaphore = new SemaphoreSlim(Environment.ProcessorCount * someMagicNumber); 
foreach (var result in StreamResults()) 
{ 
    semaphore.Wait(); 
    var task = DoWorkAsync(result).ContinueWith(t => semaphore.Release()); 
    ... 
} 

這是爲了避免將太多的結果帶入內存,並且程序無法應付(通常通過OutOfMemoryException證明)。儘管代碼工作正常並且性能合理,但仍然感覺不太好。特別是someMagicNumber乘數,它雖然通過分析進行調整,但可能並不盡如人意,並且也不適應DoWorkAsync的實施變化。

以同樣的方式,線程池可以克服安排許多事情執行的障礙,我希望能夠克服根據可用資源將許多事情加載到內存中的障礙。

由於確定性地不可能確定OutOfMemoryException是否會發生,我明白我所尋找的可能只能通過統計方式實現,或者根本不可能實現,但是我希望我錯過了一些東西。

+0

你介意DoWorkAsync()是否被實際同步執行?你可以使用C#5嗎?這與'收益率回報'有什麼關係? – svick

+0

@svick我寧可DoWorkAsync同步執行,因爲執行網絡IO並且可以使用完成端口線程。 yield-return被標記爲簡單因爲它是如何返回'StreamResults'的結果。我不能使用.C#5(或者4.5,或者MS現在調用它的任何版本!),只需C#4.0 –

+0

它被稱爲C#5.0,它將與.Net 4.5一起發佈。是的,.Net版本號可能會令人困惑。 – svick

回答

1

在這裏,我想說,你可能會推翻這個問題。過沖的後果相當高(程序崩潰)。太低的後果是,程序可能會減慢。只要你仍然有一些超出最小值的緩衝區,進一步增加到緩衝區通常幾乎沒有效果,除非管道中任務的處理時間非常不穩定。

如果你的緩衝區不斷填滿,通常意味着管道中的任務執行得比其後的任務快得多,所以即使沒有相當小的緩衝區,它也可能始終確保任務跟隨它有一些工作。獲得緩衝區90%好處所需的緩衝區大小通常會非常小(可能有幾十個項目),而獲得OOM錯誤所需的一側就像6+ 大於的訂單。只要你處在這兩個數字之間的某個位置(這是一個非常大的範圍),你就會很好。

只要運行你的靜態測試,選擇一個靜態數字,或許爲「以防萬一」增加幾個百分點的額外數值,你應該很好。至多,我會將一些幻數移到配置文件中,以便在輸入數據或機器規格發生根本性變化的情況下,可以在不重新編譯的情況下更改它們。

+0

我認爲這個問題不是關於緩衝區的大小,而是關於並行執行的事情。 – svick

+0

@svick這是關於兩個。有許多相關的操作,並行運行,創建管道。當一個任務完成一個工作單元時,它將結果傳遞給下一個任務,該任務完成另一個工作單元,並將其傳遞給管道中的下一個操作員。所有這些任務都在同一時間工作。每個任務之間都有一個緩衝區,這樣在開始下一個工作單元之前,他們不需要等待下一個任務接收結果;這減少了等待時間,如果這些任務都不需要完全相同的時間來完成他們的工作。 – Servy

+0

我不確定你在說什麼,但我確定它不是有問題的代碼。這沒有任何管道或類似的東西。 – svick