На вопрос трудно ответить, если неясно, что находится внутри вращающейся петли while(true)
. Если вы запустите 10 потоков, каждый из которых будет вращаться без каких-либо ожиданий (используя что-то вроде AutoResetEvent.WaitOne()
, Thread.Sleep()
и т. Д.), ЦП будет израсходован - поскольку вы запрашиваете его у ЦП.
Для улучшения общей производительности потоки не должны вращаться, если это не является абсолютно необходимым - и в большинстве случаев это не так. Потоки должны выполнять свою работу, а затем, если работы больше нет, они должны идти спать. Они должны быть разбужены, только если у них есть больше рабочих элементов для обработки. Если ваш поток работает все время - проверяя некоторые условия, которые встречаются только время от времени , и если у вас есть механизм, чтобы сообщить вашему потоку, что условия выполняются - тогда вращение тратит впустую циклы вашего процессора .
Концептуально поток должен работать таким образом.
while(true)
{
// Wait until a thread has something meaningful to do. Waiting can be done for instance by calling AutoResetEvent.WaitOne().
// Do a meaningful work here.
}
Если вы выполняете свой код потока таким образом, когда поток ожидает, он не тратит процессор, поэтому система не перегружена, и другие потоки / процессы могут выполнять свою работу.
Основной вопрос здесь заключается в том, есть ли у вас какой-то механизм уведомления, который позволяет вашему потоку просыпаться при поступлении нового рабочего элемента. Например, большинство операций ввода-вывода, таких как TCP-сокеты, HTTP-связь, чтение из файлов и т. Д., Поддерживают асинхронную связь, которая позволяет вашему потоку переходить в спящий режим и активироваться только при поступлении новых данных.
С другой стороны, если у вас нет такого механизма - например, вы используете стороннюю библиотеку, которая не уведомляет вас, когда что-то значимое произошло, вы должны выполнить какое-то вращение. Но даже в этом случае вопрос состоит в том, как часто вам нужно проверять, были ли выполнены условия - так что есть над чем поработать.
Если, скажем, вам нужно проверять только каждую секунду, выполняются ли условия, добавьте вызовы Thread.Sleep(1000)
в ваш код потока. Это значительно увеличивает общую производительность. Даже Thread.Sleep(0)
намного лучше, чем вращение без ожидания.
Одно важное замечание здесь. В современном C # потоки не должны использоваться в качестве основного механизма асинхронного программирования. Использование асинхронного программирования на основе задач с использованием class Task
реализовать гораздо проще, особенно если вы используете ключевые слова await-async
C # и в большинстве случаев приводит к повышению производительности.
Задачи используют потоки, которые внутренне создают новые, если слишком много рабочих элементов для обработки с текущим числом потоков и освобождают потоки, если не хватает работы. Оптимальное количество потоков снижает общее потребление памяти.
В настоящее время практически все стандартные API .NET поддерживают асинхронное программирование на основе задач, поэтому он должен быть вашим основным инструментом для достижения параллельного выполнения вашего кода.
Здесь - пример асинхронного программирования на основе задач.