我的生產者/消費者模式簡而言之,如下所示。
public class Consumer<T>
{
Task consumer;
BlockingCollection<T> buffer;
public Consumer()
{
buffer = new();
consumer = Task.Factory.StartNew(
x => ConsumerAction(),
TaskCreationOptions.LongRunning);
}
public void ConsumerAction()
{
while(true)
{
// log 1
var obj = buffer.Take();
// log 2
WriteToDisk(obj);
// log 3
}
}
public void Enqueue(T obj)
{
buffer.Add(obj);
}
}
該Consumer型別按預期作業了一段時間,然后在一個看似隨機的點上,它停止運行Take,并且buffer繼續增長。在同一個輸入集合上,有時它在整個輸入中都可以正常作業,有時會在輸入的開頭中斷,有時在結尾處中斷。
- 我嘗試在執行路徑中涉及的任何方法中捕獲任何可能的例外,但沒有引發例外;
- 我已經檢查了我的應用程式中的日志,因此,最后一次的所有業務邏輯都已
obj成功執行,因此呼叫已回傳var obj = buffer.Take();并正在等待添加新專案buffer; - 我已經嘗試將
while(true), 封閉在一個try-catch塊中,并且沒有捕獲到例外; - 代碼示例中的注釋日志在日志中按以下順序出現:
1,2,3, ...3,1.
我的具體問題是:
- 垃圾收集器是否有可能正在收集執行緒?
while(true)可能是錯誤的來源?!- 關于如何最好地除錯這個有什么想法嗎?
- 成功運行處理整個輸入集合大約需要 12 小時,并且添加了超過 10 億個專案
buffer(但如果Take有效,buffer在給定時間僅包含少數專案)。這個比例是否似乎是這種模式的一個極端案例/不是它的預期用途?
根據評論中的要求,我將提供一個最小的可重現示例。然而,這有點挑戰性,因為我不確定程式的哪些部分是相關的,所以可能需要一些時間來縮小范圍。同時,我很感激對上述問題的任何建議。
uj5u.com熱心網友回復:
垃圾收集器是否有可能正在收集執行緒?
不,GC 收集記憶體中的物件,而不是執行緒。
while(true) 可以成為錯誤的來源嗎?!
不,但我建議使用GetConsumingEnumerable將其替換為 foreach 回圈。這將允許您通過在緩沖區上呼叫 CompleteAdding 來干凈、輕松地退出回圈。
關于如何最好地除錯這個有什么想法嗎?
我肯定會添加一個 try/catch 以確保WriteToDisk不會以某種方式失敗。您還應該在完成后檢查任務,以確保沒有發生其他故障。您可以考慮的另一件事是對緩沖區的大小添加限制。這應該限制記憶體使用,幫助防止執行緒饑餓,并且如果專案沒有從緩沖區中洗掉,應該掛起你的程式。最后一點有助于除錯,因為您可以在該點簡單地中斷行程并檢查每個執行緒在做什么。
猜測是可能存在某種死鎖或其他問題,導致 ConsumerAction 執行緒在內部阻塞WriteToDisk。
成功運行處理整個輸入集合大約需要 12 小時,超過 10 億個專案被添加到緩沖區(但如果 Take 作業,緩沖區在給定時間只包含少數專案)。這個比例是否似乎是這種模式的一個極端案例/不是它的預期用途?
對我來說,對于阻塞集合來說,這似乎是一個非常好的用法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/467453.html
上一篇:添加兩個$post->變數
