Максимальное количество потоков в приложении .NET?

140

Какое максимальное количество потоков вы можете создать в приложении C #? И что происходит, когда вы достигаете этого предела? Это исключение какого-то рода?

Джон Сондерс
источник
Ответ будет другим, если вы работаете на 64-разрядной или 64-разрядной виртуальной машине
Брайан Р. Бонди
В моей ситуации это x86, но можете ли вы дать ответ на оба вопроса, если это кому-то еще нужно?

Ответы:

145

Там нет врожденного ограничения. Максимальное количество потоков определяется количеством доступных физических ресурсов. Смотрите эту статью Раймонда Чена для деталей.

Если вам нужно спросить, каково максимальное количество потоков, вы, вероятно, делаете что-то не так.

[ Обновление : Просто из интереса: .NET Thread Pool по умолчанию номера потоков:

  • 1023 в Framework 4.0 (32-разрядная среда)
  • 32767 в Framework 4.0 (64-битная среда)
  • 250 на ядро ​​в Framework 3.5
  • 25 на ядро ​​в Framework 2.0

(Эти цифры могут отличаться в зависимости от оборудования и ОС)]

Митч Пшеничный
источник
13
Как ты это понял? Вы знаете, что такое .NET 4.5 или что будет 5.0?
goodguys_activate
3
Вы можете использовать этот код для подсчета: int workerThreads; int завершенииPortThreads; ThreadPool.GetMaxThreads (out workerThreads, out completePortThreads);
JALLRED
1
@MitchWheat Мне было интересно, потому что связанная статья не обсуждает .NET, но просто 'C.
pqsk
1
@LoukMo: если вы не можете создать поток, значит, у вас недостаточно памяти! Я не пробовал это, но я предполагаю, что исключение памяти будет брошено ....?
Митч Пшеница
1
@Liam Ссылка теперь должна быть исправлена.
Евгений Комисаренко
26

Митч прав. Это зависит от ресурсов (памяти).

Хотя статья Рэймонда посвящена потокам Windows, а не потокам C #, логика применяется одинаково (потоки C # отображаются на потоки Windows).

Однако, поскольку мы находимся в C #, если мы хотим быть абсолютно точными, нам нужно различать «запущенные» и «незапущенные» потоки. Только запущенные потоки фактически резервируют пространство стека (как мы могли ожидать). Незапущенные потоки распределяют только информацию, требуемую объектом потока (вы можете использовать отражатель, если заинтересованы в реальных членах).

Вы можете проверить это сами, сравните:

    static void DummyCall()
    {
        Thread.Sleep(1000000000);
    }

    static void Main(string[] args)
    {
        int count = 0;
        var threadList = new List<Thread>();
        try
        {
            while (true)
            {
                Thread newThread = new Thread(new ThreadStart(DummyCall), 1024);
                newThread.Start();
                threadList.Add(newThread);
                count++;
            }
        }
        catch (Exception ex)
        {
        }
    }

с участием:

   static void DummyCall()
    {
        Thread.Sleep(1000000000);
    }

    static void Main(string[] args)
    {
        int count = 0;
        var threadList = new List<Thread>();
        try
        {
            while (true)
            {
                Thread newThread = new Thread(new ThreadStart(DummyCall), 1024);
                threadList.Add(newThread);
                count++;
            }
        }
        catch (Exception ex)
        {
        }
    }

Поместите точку останова в исключение (вне памяти, конечно) в VS, чтобы увидеть значение счетчика. Конечно, есть очень существенная разница.

антонио
источник
9

Я провел тест на 64-битной системе с консолью c #, исключение составляет тип нехватки памяти, использующий потоки 2949.

Я понимаю, что мы должны использовать пул потоков, что я и делаю, но этот ответ является ответом на главный вопрос;)

MadApples
источник
6

Вы должны использовать пул потоков (или асинхронные delgates, которые, в свою очередь, используют пул потоков), чтобы система могла решить, сколько потоков должно выполняться.

Ян Бойд
источник
Ответ является , чтобы позволить системе решать.
Ян Бойд
@Ian: Я понизил тебя, потому что тот же самый ответ был дан девять месяцев назад.
Джон Сондерс
11
Ссылка на сайт. я не вижу упоминания о пуле потоков как чей-либо ответ.
Ян Бойд
4

Джефф Рихтер в CLR через C #:

«В версии 2.0 CLR максимальное число рабочих потоков по умолчанию равно 25 для каждого процессора в машине, а максимальное число потоков ввода-вывода по умолчанию равно 1000. Ограничение 1000 фактически не ограничено».

Обратите внимание, что это основано на .NET 2.0. Это могло измениться в .NET 3.5.

[Редактировать] Как заметил @Mitch, это относится к CLR ThreadPool. Если вы создаете темы, смотрите комментарии @Mitch и другие.

ясень
источник
Вы путаете CLR 2.0 и .NET 2.0 в своем комментарии о .NET 3.5.
bzlm
Насколько я знаю, SP1 для .NET 2.0 (часть .NET 3.5) изменил значение рабочих потоков по умолчанию на 250 на процессор / ядро ​​для пулов потоков.
Михаил Даматов
0

Вы можете проверить это, используя этот код:

private static void Main(string[] args)
{
   int threadCount = 0;
   try
   {
      for (int i = 0; i < int.MaxValue; i ++)
      {
         new Thread(() => Thread.Sleep(Timeout.Infinite)).Start();
         threadCount ++;
      }
   }
   catch
   {
      Console.WriteLine(threadCount);
      Console.ReadKey(true);
   }
}

Остерегайтесь 32-битного и 64-битного режима применения.

Юша Алеауб
источник