在我的C#/ .net 3.5程序中,我使用線程池線程(委託+ BeginInvoke/EndInvoke)並行化和加快一些文件加載。 SystemInternals工具ProcessExplorer顯示進程中的線程數量隨時間增加,而我期望保持不變。看起來像一些線程/線程處理呆在無處不在。有趣的是,我無法找到線程如何增長,似乎偶爾發生,每次啓動應用程序時都沒有可重複的模式。我花了一些時間來分析和這裏有一些意見:線程沒有垃圾收集/線程池線程/ C#/ .net
1)代碼如下所示:
ArrayList IAsyncResult_s = new ArrayList();
AsyncProcessing thread1 = processRasterLayer;
... ArrayList filesToRender....
foreach (string FileName in filesToRender)
{
string fileName2 = FileName;
GeoImage partialImage1;
IAsyncResult asyncResult = thread1.BeginInvoke(
fileName2, .....,
out partialImage1, ..., null, null);
IAsyncResult_s.Add(asyncResult);
asyncResult = null;
}
.................
//block and render all
foreach (IAsyncResult asyncResult in IAsyncResult_s)
{
GeoImage partialImage1;
thread1.EndInvoke(
out partialImage1, , asyncResult);
//render image.. some calls to render partial image here
partialImage1.Dispose();
partialImage1 = null;
}
IAsyncResult_s.Clear();
IAsyncResult_s = null;
thread1 = null;
2)處理線程數 我的跟蹤表明,內循環執行過程中,ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
給數字如493和1000. 循環結束時,ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
給出數字500,1000。因此,可用的線程數返回到相同的數 報告的進程線程數SystemInternals ProcessExplorer
和API System.Diagnostics.Process.GetCurrentProcess()
.Threads.Count是循環前16次,循環後大約21次。 如果我調用那些循環,正在處理的線程數會增加,但不是每次修復nubmer,但是每當我重複上面的代碼時增加1到4,所以像16-> 21-> 22-> 26-> 31 ...
3)強制垃圾收集沒有htelp 我試圖去掉垃圾回收來擺脫那些額外的線程,但是這並沒有將它們從進程中移除。
4)配置工具 我使用的是RedGates內存和性能分析器,但沒有找到明顯的原因。我看到幾個額外的threas和它們的對象(ThreadContext等)掛起,但沒有看到在內存中保存這些線程的對象。我很確定那些額外的線程涉及到循環工作上面,因爲我在調用中添加了線程名稱,並且他們仍然有我給他們的名字。
5)Intelitrace Intelitrace調試也顯示額外的線程掛起。他們仍然有我給他們的名字。但有趣的是,它也顯示了現在掛起的同一個線程,在過去的循環中被使用過,而且同一個線程正在執行一些與定時器相關的evens,這些evens來自我的代碼的定時器。
6)定位問題 所以,當我在上面禁用循環這個過程filse Asynchroniously,並加載文件sequentialy,我也沒有額外的線程,並在我的應用程序線程的數量是恆定的,並和周圍16
7)關於SetMaxThreads:它在這裏的樣子我的機器(XP,.NET 3.5)上:
這樣的代碼:
ThreadPool.GetAvailableThreads(出AvailableWorkerThreads,出AvailableCompletionPortThreads);
ThreadPool.GetMaxThreads(out MaxWorkerThreads,out MaxCompletionPortThreads);
ThreadPool。GetMinThreads(輸出MinWorkerThreads,輸出MinCompletionPortThreads);
給出結果:
MinWorkerThreads:2個MaxWorkerThreads:500個MinCompletionPortThreads:2個MaxCompletionPortThreads:1000個AvailableWorkerThreads:500個AvailableCompletionPortThreads:1000
我的應用程序被同時使用也許8個工作線程。我發現SetMaxThreads沒有問題。
8) 從功能上來說,到目前爲止,在上面的解決方案中我沒有問題。但不知何故,如果工具報告我的應用程序中的線程數量正在增加,它看起來像某種「資源泄漏」,我想解決它。它看起來像一些線程手柄無故懸掛。
9)下面是一篇有趣的文章。調用EndInvoke後,清理線程資源變得很簡單。我在我的代碼中這樣做。文章sasy:..「。由於EndInvoke在派生線程後清除,所以必須確保爲每個BeginInvoke調用EndInvoke。「」如果線程池線程已退出,EndInvoke將執行以下操作:清除退出線程的鬆散結束並處理其資源「見:http://en.csharp-online.net/Asynchronous_Programming%E2%80%94BeginInvoke_EndInvoke
10)另一個有趣的文章。作者說他有線程處理泄漏,因爲他從非gui線程創建控件。這是相當複雜的文章,請參閱:http://msmvps.com/blogs/senthil/archive/2008/05/29/the-case-of-the-leaking-thread-handles.aspx
11)另一個有趣的文章。它講述了ThreadPool.SetMinThreads屬性。看起來它不是ThreadPool.SetMaxThreads,而是ThreadPool.SetMinThreads,它可以對ThradPool進行有用的控制。這篇文章讓我大開眼界,讓我想到了ThreadPool的工作原理和性能問題。文章是:http://www.dotnetperls.com/threadpool-setminthreads。另一個類似的是:http://www.codeproject.com/Articles/3813/NET-s-ThreadPool-Class-Behind-The-Scenes
12)另一個有趣的文章。它正在討論ThreadPool的限制問題。文章提到每秒增加2個新線程的ThreadPool限制。請參閱http_://社交。 MSDN。微軟。 com/forums/en-US/clr/thread/3325cb32-371b-4f3e-965f-6ca88538dc3e/
13)所以,在30次測試中,我看到只有2次分配的線程數會縮小。但是,它確實發生了。我看到一次線程號碼變成16 - > ....-> 31-> 61-> - > 30-> 16。因此,它回到了16.它不會經常發生,也不是等待時間,它像是在進行中的大型活動,隨後是一段持續低水平的活動。
14)ThreadPool.SetMinThreads方法文檔。它討論了每個線程池2個新線程的限制。目前尚不清楚設置此屬性是否會消除該限制。 HTTP_://msdn.microsoft。 COM/EN-CA /庫/系統。 threading.threadpool.setminthreads(v = vs.90).aspx
您是否管理每個線程上的大對象? – 2013-03-17 09:09:57
這是什麼問題呈現? – 2013-03-17 09:38:19
我可能是錯的..但AFAIK'線程'不是由GC管理的東西。線程由ThreadPool管理。當你對它做更多的工作時,ThreadPool會創建更多的線程。而且隨着工作負載的降低,它決定是否釋放一些線程,或者繼續保留它們以便將來可能會投入的更多工作。我會說你在工作負載完成後給.NET一些時間(比如5-7分鐘),然後再次對線程進行計數。到那個時候,如果你(任何其他你使用的庫)沒有安排更多的工作,.NET會決定讓這些線程去。但我可能是錯的。 – Madushan 2013-03-17 09:54:42