Исследование — сколько потоков может создать ОС Windows у вас?
Invite pending
Эксперимент
Создаем новое консольное приложение. Вставляем следующий код:
private static void ThreadOverhead() {
const Int32 OneMB = 1024 * 1024; // размер одного мегабайта
using (ManualResetEvent wakeThreads = new ManualResetEvent(false)) {
Int32 threadNum = 0;
try {
while (true) {
Thread t = new Thread(WaitOnEvent);
t.Start(wakeThreads);
Console.WriteLine("{0}: {1}MB", ++threadNum,
Process.GetCurrentProcess().PrivateMemorySize64 / OneMB);
}
}
catch (OutOfMemoryException) {
Console.WriteLine("Out of memory after {0} threads.", threadNum);
Debugger.Break();
wakeThreads.Set(); // гасим все потоки
}
}
}
private static void WaitOnEvent(Object eventObj) {
((ManualResetEvent)eventObj).WaitOne();
}
Запускаем ThreadOverhead на исполнение:
public static void Main() {
ThreadOverhead();
}
И наблюдаем результат, для моей системы это выглядит так:
1333: 103MB
1334: 103MB
1335: 103MB
1336: 103MB
1337: 103MB
1338: 103MB
1339: 103MB
1340: 103MB
1341: 103MB
1342: 103MB
1343: 104MB
1344: 104MB
1345: 104MB
1346: 104MB
1347: 104MB
1348: 104MB
1349: 104MB
1350: 104MB
1351: 104MB
1352: 104MB
1353: 104MB
1354: 104MB
1355: 104MB
1356: 104MB
1357: 104MB
1358: 104MB
1359: 105MB
1360: 105MB
Out of memory after 1360 threads.
Кстати — обратите внимание как постепенно начинает «тормозить» программа. Чем ближе к концу свободной памяти и больше потоков — тем выше накладные расходы на выделение этой памяти и особенно на переключение контекста между потоками (Context switching).
А какая от этого польза?
Казалось бы — эксперимент «о сферических конях в вакууме», но не спешите с выводами. Так например если посмотреть разницу между масштабируемым и не масштабируемым web-сервером, то там возникает точно такая же ситуация, только потоки создаются не нами, а ThreadPool-ом web-сервера IIS от Майкрософт. И понимание как происходит перегрузка IIS блокированными потоками я надеюсь многим поможет избежать этой ситуации в продакшене.