Windows Server 2003 上的后台工作程序限制

发布于 2024-08-04 11:09:14 字数 2196 浏览 3 评论 0原文

目前,我在 Windows Server 2003 上运行 BackgroundWorker 时遇到问题。我有一个窗口应用程序需要运行超过 50 个线程

我编写的代码使用 BackgroundWorker(BW) 作为线程包装器将数据更新到窗口窗体上。问题是该代码能够在我的 XP 计算机上运行超过 50 个 BW,但在 Windows 2003 服务器上运行时会停止在 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<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服务器上可以运行的BW实例数量有限制,而XP上却没有?我是否可以增加 2003 服务器上的 BW 实例数量?如果是,我该怎么做?

I am currently having an issue with BackgroundWorker running on Windows Server 2003. I have a window application that need to run more than 50 threads.

The code I wrote use BackgroundWorker(BW) as a Thread wrapper to update data onto a window form. The issue is that the code are able to run more than 50 BWs on my XP machine, but stop at 50 when running on Windows 2003 server.

At first I though there are some kind of limit on the number of thread per app can run. Googling the issue shows that is not the case. I wrote the following code to confirm that.

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);
}

The result show as expected. I can see a list of number from 0 to 54 on both my XP machine and the 2003 server.

However, when I try using the BW instead, my XP machine run to 54 and the 2003 server run to 49 (50 BWs). Here is the code.

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);
}

So, the question is that why there is a limit on number of BW instances can run on the 2003 server but not XP? Is there anyway I can increase the number of BW instances on 2003 server? If yes, how can I do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

这个俗人 2024-08-11 11:09:14

对于您正在做的工作类型来说,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 会限制线程创建,例如每 500 毫秒创建一个新线程。

你们的两个系统运行的框架版本是否完全相同(包括SP)?它们的核心数量相同吗?

请注意,线程具有相当大的开销,并且通常不值得创建比核心数量多得多的线程。如果您的瓶颈位于 CPU 之外(例如,您正在与多个远程系统通信),那么拥有数十个线程可能是值得的。如果您正在进行 CPU 密集型计算,则事实并非如此。如果您受磁盘 IO 限制,请注意不要用大量并行操作来破坏磁盘。

BackgroundWorker is an inappropriate choice for the kind of work you're doing - it's intended as a means to spin off a (usually single) worker thread while keeping your UI responsive. the worker threads are provided with easy means to interact with your UI - I doubt you have 50 threads all touching your UI.

Consider using threads directly instead. The ThreadPool makes this easy. From 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.");
    }
}

You're seeing a 50-thread limit because some versions of the CLR have a default limit of 25 ThreadPool threads per core. Thus, on a dual-core CPU, 50 threads. You can bump this up with ThreadPool.SetMaxThreads. I believe that newer versions of the CLR set the default much higher. Note also that the ThreadPool throttles thread creation, to something like one new thread per 500ms.

Are your two systems running exactly the same version of the framework (including SP)? Do they have the same number of cores?

Note that threads have a considerable overhead, and it's often not worthwhile to create significantly more threads than you have cores. If your bottleneck is off-CPU (say, you're talking to multiple remote systems), then having dozens of threads might be worthwhile. If you're doing CPU-bound calculations, then it's not. If you're disk-IO-bound, be careful that you're not thrashing your disk with that number of parallel operations.

饭团 2024-08-11 11:09:14

正如Michael Petrotta所说,BackgroundWorker 实际上只是用于单个工作线程,以保持 UI 响应。

如果您有很多线程,ThreadPool 很有用短期行动,但并不是真正打算运行许多长期行动。默认最大线程数取决于 CLR 版本(从 2.0 SP1 开始每个 CPU 250 个,之前每个 CPU 25 个)。您可以使用 ThreadPool.SetMaxThreads,但我不推荐这个。

如果您有 50 多个长期的、受 CPU 限制的操作需要并行执行,我认为最好的选择是创建一个 Thread 并使用 AsyncOperation (SynchronizationContext)来更新您的 UI。

As Michael Petrotta said, the BackgroundWorker is really just for a single worker thread to keep your UI responsive.

The ThreadPool is useful if you have a lot of short-lived actions, but not really intended to run many long-lived actions. The default max number of threads depends on the CLR version (250 per CPU starting with 2.0 SP1, 25 per CPU before). You can increase this number with ThreadPool.SetMaxThreads, but I wouldn't recommend this.

If you have 50+ long-lived, CPU-bound actions that need to be executed in parallel, I think the best option is to create a Thread for each and use an AsyncOperation (SynchronizationContext) to update your UI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文