我們有一個常見的日誌記錄問題,我們做3種類型的日誌記錄(讓我們說:跟蹤,審計,計數)是我們記錄的3個方面。我們同時從REST Web服務中運行的代碼爲每個請求提供所有請求。生產者 - 消費者多個生產者多個隊列單個消費者
對於每個請求,我們會對每個日誌記錄區域進行多次調用。比方說,平均每個Web請求約100次日誌調用,一些跟蹤,一些審計,一些計數器,總共100次調用,每個Web請求。每個日誌記錄調用都會將一些數據寫入某個存儲以供稍後處理[不重要的是該存儲是什麼,但將其存入該存儲肯定是I/O綁定的 - (實際上它是一個天藍色的隊列,因此它是跨網間的HTTP調用) ]。
我們的問題是,記錄任何信息(3個區域中的任何一個)的行爲會使服務請求線程太長而無法寫入所有日誌接收器100次。我們已經測量了請求處理時間花費在記錄接收器上的時間的四分之三。所以,你可以看到我們需要顯着優化!
我們想加快速度,並從日誌寫入中釋放請求線程。我們希望使用另一個線程在後臺按自己的步調將日誌記錄數據寫入3個日誌記錄存儲區。所以我們認爲將日誌記錄排隊寫入內存隊列中,以便日誌寫入線程可以並行處理它們併發出多個請求,這是一條路。
Stephen Cleary的書「C#Cookbook中的併發」(fab參考)指出,在這種情況下使用像BlockingCollection<T>
這樣的阻塞集合是理想的。因此,一次一個線程可以生成數據(並寫入內存隊列),另一個線程可以使用內存隊列中的數據。似乎這對我們的情況是理想的。然而,在我們的例子中,因爲我們運行在ASP.NET主機中,並且線程池線程對於Web服務器非常寶貴(爲了可伸縮性),我們只希望有一個線程專用於[消費]全部3個日誌隊列。讓所有其他線程處理入站Web請求,並[生成]記錄數據。
所以問題變爲:如何使用的BlockingCollection<T>
3個實例(每個類型的日誌記錄),並支持:
- 任何用於產生數據的生產者[呼入web請求線程]的
- 一個單獨的(專用)日誌線程使用者,可以持續有效地使用所有三個隊列。
任何人都可以想到一個設計模式,可以在這裏工作嗎?對我們來說缺少的一件事是消費者如何有效地清空所有三個隊列,而不會阻塞任何隊列,並且不斷處理所有三個隊列。
你可以有一個'BlockingCollection'其中'T'是一些自定義的類,可以包含任何三種類型。您可以在此類型中使用枚舉來檢測此類真正擁有哪種類型。 –
謝謝,但我沒有看到你的回答,我們如何處理所有三個'BlockingCollection'隊列與同一個消費者線程,連續不等待任何一個隊列。 –
我建議你有一個'BlockingCollection',而不是三個。 –