Чем ограничено количество тасков / потоков выполнения?
Чем ограничено количество тасков / потоков ?
Почему я не могу выполнять работу например в 1000 тасках / потоков
Почему это бессмыслица выполнять в 1000 потоков ?
int maxThreads = Environment.ProcessorCount * 2
Console.WriteLine(maxThreads);
Получаю 64
Т.е. я ограничен 64 потоками выполнения ?
Я запускал так, казалось быстрее xD
for (int i = 0; i < 100; i++)
{
int j = i;
new Thread(() => Algoritm(j)).Start();
}
for (int i = 0; i < 100; i++)
{
int j = i;
Task.Run(() => Algoritm(j));
}
Ответы (3 шт):
Здравый смысл.
Вы можете заказать 64 шиномонтажникам поменять 64 колеса. Каждый будет при деле. А можете заказать и 6400 колес поменять одновременно, и они будут большую часть времени между ними метаться, практически не выполняя полезной работы. Точно так же и с другими компьютерными ресурсами (обычно под ними понимается CPU, но может быть и Диск и GPU). Ниже речь о CPU-ограниченных задачах.
Откуда взялась цифра "количество_ядер * 2"?
Насколько мне известно, число "2" получено эмпирически. Т.е. ядро может выполнять примерно 2 потока поочередно, пока один ждет что-то из кеша или памяти, например, в это время второй может производить вычисления (см. Hyper-threading). Когда-то больше, когда-то меньше, но обычно - 2.
Имеет ли смысл стартовать 300 потоков?
Зависит от типа процесса и архитектуры программы. Например, вам может быть нужно получать отклик от удаленной системы, вы отправляете запрос и .. долго долго ждёте. То есть вы можете отправить 300 запросов и только потом начнут приходить какие-то ответы. Выделять для этого 300 потоков может быть не оптимальным архитектурным решением, но иногда это проще и лучше масштабируется, чем переписывать программу на асинхронную/заявочную работу. (Заметьте, в этом месте задача перестала быть CPU-ограниченной) Тут в качестве примера можно привести ОС - грубо говоря, она стартует каждую программу в своем потоке, и каждый поток 99% времени бездействует.
Я запускал так, казалось быстрее xD
В приведённом фрагменте кода вы только запускаете потоки и задачи, но не ждёте их завершения. Таким образом вы можете и миллион потоков/задач запустить и они моментально "выполнятся", это абсолютно ничего не говорит об эффективности одновременного запуска потоков/задач.
Допускаю, что вы привели просто не весь код, но в случае с многопоточностью и асинхронностью критически важно, чтобы код был корректно написан, иначе можно легко получить абсолютно не релевантные результаты.
А по сути дела - нужно смотреть, какой код вы выполняете в потоках/задачах, насколько он "тяжёлый", что именно он делает - тяжёлые вычисления или он просто ждёт окончания ввода/вывода, соответственно нужно грамотно делить работу на части и использовать либо многопоточность (в разумных пределах, чтобы все ресурсы не ушли на постоянное переключение между потоками) для тяжёлых вычислительных задач, либо асинхронность для задач, упирающихся в ожидание завершения операций.
Планировщик тратит на переключение контекста потока 1/3 выделенного ему кванта, о чём пишет Д.Рихтер в своей книжке "..для профессионалов". Соответственно полезное время обратно-пропорционально количеству потоков, но только в том случае, если эти потоки выполняют одну задачу. Если-же каждый поток занимается своим делом, то расходы на их переключение вполне окупаются. ООО-ядра с гипертредингом не напрягаясь способны обрабатывать не более 4-х потоков за раз при условии, что в коде будут присутствовать не только целочисленные инструкции CPU, но и активно задействован FPU, на котором исполняются команды SIMD (AVX/SSE/MMX etc). Внутри одного ядра, CPU и FPU имеют разные блоки Execute (см.микро-архитектуру), и в большинстве случаях FPU простаивает на 70-80%.
Системы класса Win выделяют для каждого потока макс. 1 Мб стековой памяти. Это накладывает ограничение на общее их кол-во. Например, пространство памяти юзера на системах х32 занимает нижнюю половину до 0x80000000, т.е. 2 гигабайт из четырёх. Если каждый поток затребует от этой памяти по 1 Мб, то получается, что её резерва хватит всего на 2000 потоков. Однако на практике, тред возбуждает исключение "Exсeption_Stack_Overflow" (переполнение) уже на 256 Кбайтах, что увеличивает общее число в 4 раза = 8000. На системах х64 такого ограничения нет.