[英]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.