Ограничение BackgroundWorker на Windows Server 2003 - PullRequest
0 голосов
/ 09 сентября 2009

У меня сейчас проблема с BackgroundWorker, работающим на Windows Server 2003. У меня есть оконное приложение, которое должно работать более 50 threads.

Код, который я написал, использует BackgroundWorker (BW) в качестве оболочки Thread для обновления данных в форме окна. Проблема заключается в том, что код способен запускать более 50 BW на моем компьютере с XP, но останавливается на 50 при работе на сервере Windows 2003.

Сначала я подумал, что существует ограничение на количество потоков, которое может запускать приложение. Поиск в Google показывает, что это не так. Я написал следующий код, чтобы подтвердить это.

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

Результат показывается, как и ожидалось. Я вижу список чисел от 0 до 54 как на моем компьютере с XP, так и на сервере 2003 года.

Однако, когда я пытаюсь использовать 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);
}

Итак, вопрос в том, почему существует ограничение на количество экземпляров BW, которые могут работать на сервере 2003, но не на XP? Могу ли я в любом случае увеличить количество экземпляров BW на 2003 сервере? Если да, как я могу это сделать?

Ответы [ 2 ]

3 голосов
/ 09 сентября 2009

BackgroundWorker - неподходящий выбор для той работы, которую вы выполняете - он предназначен как средство выделения (обычно единственного) рабочего потока при сохранении отзывчивости вашего пользовательского интерфейса. рабочие потоки обеспечиваются простыми средствами взаимодействия с вашим пользовательским интерфейсом - я сомневаюсь, что все 50 потоков касаются вашего пользовательского интерфейса.

Попробуйте вместо этого использовать потоки напрямую. 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 на ядро. Таким образом, на двухъядерном процессоре 50 потоков. Вы можете увеличить это с ThreadPool.SetMaxThreads. Я считаю, что более новые версии CLR устанавливают значение по умолчанию намного выше. Также обратите внимание, что ThreadPool ограничивает создание потоков, например, один новый поток на 500 мс.

Ваши две системы работают с одинаковой версией фреймворка (включая SP)? У них одинаковое количество ядер?

Обратите внимание, что потоки имеют значительные накладные расходы, и часто не стоит создавать значительно больше потоков, чем у вас ядер. Если у вас узкое место вне процессора (скажем, вы разговариваете с несколькими удаленными системами), тогда может быть полезно иметь десятки потоков. Если вы выполняете вычисления, связанные с процессором, то это не так. Если вы ограничены дисковым вводом-выводом, будьте осторожны, чтобы не перегружать диск таким количеством параллельных операций.

1 голос
/ 09 сентября 2009

Как сказал Майкл Петротта , BackgroundWorker действительно предназначен только для одного рабочего потока, чтобы поддерживать отзывчивость вашего пользовательского интерфейса.

ThreadPool полезен, если у вас много кратковременных действий, но они не предназначены для выполнения многих долгоживущих действий. Максимальное количество потоков по умолчанию зависит от версии CLR (250 на процессор, начиная с 2.0 SP1, 25 на процессор раньше). Вы можете увеличить это число с помощью ThreadPool.SetMaxThreads , но я бы не рекомендовал это.

Если у вас есть более 50 долгоживущих, связанных с процессором действий, которые нужно выполнять параллельно, я думаю, что лучшим вариантом будет создать Thread для каждого и использовать AsyncOperation ( SynchronizationContext ) для обновления вашего пользовательского интерфейса.

...