[英]BackgroundWorker limitation on Windows server 2003
我目前在Windows Server 2003上運行BackgroundWorker
遇到問題。我有一個窗口應用程序,需要運行50個以上的threads
。
我編寫的代碼使用BackgroundWorker
(BW)作為線程包裝器將數據更新到窗口表單上。 問題是該代碼能夠在我的XP機器上運行超過50次BW,但在Windows 2003服務器上運行時卻停止在50次。
起初,我對每個應用程序可以運行的線程數量有所限制。 谷歌搜索問題表明情況並非如此。 我編寫了以下代碼來確認這一點。
static int count = 0;
static void Main(string[] args)
{
int max = 55; // default value
if (args.Length > 0)
// use command line parameter if provided
max = Convert.ToInt32(args[0]);
List<Thread> threadList = new List<Thread>();
try
{
while (count < max)
{
Thread newThread = new Thread(
new ParameterizedThreadStart(DummyCall), 1024);
newThread.Start(count);
threadList.Add(newThread);
count++;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
static void DummyCall(object obj)
{
Console.WriteLine(obj.ToString());
Thread.Sleep(1000000000);
}
結果顯示出預期的效果。 我可以在XP機器和2003服務器上看到從0到54的數字列表。
但是,當我嘗試使用BW時,我的XP計算機運行到54,而2003服務器運行到49(50 BW)。 這是代碼。
static int count = 0;
static void Main(string[] args)
{
int max = 55; // default value
if (args.Length > 0)
// use command line parameter if provided
max = Convert.ToInt32(args[0]);
List<BackgroundWorker> list = new List<BackgroundWorker>();
try
{
while (count < max)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync(count);
list.Add(worker);
count++;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine(e.Argument.ToString());
Thread.Sleep(1000000000);
}
因此,問題在於,為什么在2003服務器上可以運行但不能在XP上運行的BW實例數量受到限制? 無論如何,我可以增加2003服務器上BW實例的數量嗎? 如果是,我該怎么做?
BackgroundWorker對於您正在執行的工作是不適當的選擇-它旨在作為一種手段(在保持UI響應能力的同時)剝離(通常是單個)工作線程。 為工作線程提供了與UI交互的簡便方法-我懷疑您有50個線程都在與UI接觸。
考慮直接使用線程。 ThreadPool使這變得容易。 從MSDN:
using System;
using System.Threading;
public class Example {
public static void Main() {
// Queue the task.
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
Console.WriteLine("Main thread does some work, then sleeps.");
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo) {
// No state object was passed to QueueUserWorkItem, so
// stateInfo is null.
Console.WriteLine("Hello from the thread pool.");
}
}
您看到50個線程的限制,因為某些版本的CLR的默認限制是每個內核25個ThreadPool線程。 因此,在雙核CPU上,有50個線程。 您可以使用ThreadPool.SetMaxThreads
增強它。 我相信較新的CLR版本會將默認值設置得更高。 還要注意,ThreadPool將線程的創建速度限制為每500ms一個新線程。
您的兩個系統運行的框架版本完全相同(包括SP)嗎? 它們具有相同數量的核心嗎?
請注意,線程具有相當大的開銷,因此創建比核心多得多的線程通常不值得。 如果瓶頸在CPU之外(例如,您正在與多個遠程系統通信),那么擁有數十個線程可能是值得的。 如果您正在執行CPU限制的計算,則不是。 如果您的磁盤受到IO的限制,請注意不要因該數量的並行操作而影響磁盤。
正如Michael Petrotta所說, BackgroundWorker實際上僅用於單個工作線程,以使您的UI保持響應。
如果您有很多短期操作,但實際上並不想運行許多長期操作,則ThreadPool很有用。 默認的最大線程數取決於CLR版本(從2.0 SP1開始每個CPU 250個,之前每個CPU 25個)。 您可以使用ThreadPool.SetMaxThreads增加此數字,但我不建議這樣做。
如果您有50多個需要並行執行的長期CPU限制動作,我認為最好的選擇是為每個動作創建一個線程並使用AsyncOperation ( SynchronizationContext )更新您的UI。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.