Диспетчер задач говорит, что система работает с более чем тысячей потоков


17

Я открыл диспетчер задач и заглянул в область «Система» и увидел:

Темы: 1337

Поскольку у меня есть двухъядерный процессор с гиперпоточностью (то есть четыре потока), как можно иметь более 1000 потоков, если в моем процессоре всего четыре?


3
Разве не поэтому они называют это гиперпоточностью ? :)
CVn

9
Ну и дела, они наконец изобрели "мультипрограммирование" ??? (Это 1967, верно?)
Даниэль Р Хикс

10
Кто-то только что изменил номер на 1337?
Эрти Сейдохл

11
Как может компания с четырьмя столами иметь 1337 сотрудников? Легко; сотрудники сменяются, используя столы.
Эрик Липперт

Ответы:


50

Ответ прост: не все потоки выполняются одновременно. Для более полного объяснения читайте дальше.

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

Однако планировщик задач на самом деле не планирует приложения (процессы), а планирует потоки . Каждое приложение имеет по крайней мере один поток, но потенциально может использовать большое количество потоков, чтобы разделить работу, которую оно выполняет, на связанные или независимые части. Например, для приложения характерно иметь один поток, который обрабатывает пользовательский интерфейс, и создавать другой поток, когда пользователь запускает потенциально длительную операцию (это могут быть такие вещи, как печать, пересчет электронной таблицы, выполнение среды разработки). поиск символа и т. д. и т. д.). Некоторые среды программирования вводят некоторое количество потоков, незаметно для программиста; например, Java и .NET могут выполнять сборку мусорав отдельном потоке, который находится вне непосредственного контроля программиста. Некоторые программы создают несколько потоков на ранних этапах и объединяют их в пул, потому что создание новых потоков - это сравнительно дорогая операция (поэтому вам не обязательно создавать поток каждый раз, когда он вам нужен). Все, что делает предварительный просмотр, обычно выполняется в отдельном потоке, поэтому остальная часть пользовательского интерфейса остается отзывчивой, пока создается предварительный просмотр. И так далее. В совокупности все это означает, что количество потоков в системе в любое время может легко во много раз превышать количество процессов.

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

Количество потоков, которое вы видите в диспетчере задач, - это общее количество потоков в любом из этих состояний. Например, в системе Windows 7, на которой я сейчас набираю, запущено около 70 процессов, но почти 900 потоков. Со всеми фоновыми процессами для обработки различных задач и того, как они, вероятно, подразделяются на множество потоков каждый, это не возмутительное число.

Если углубиться в технические аспекты реализации, в основе планировщика задач многозадачной операционной системы, как правило, лежит аппаратная обработка прерываний. Это означает , что ядро может остановить CPU , когда он не имеет никакой полезной работы для выполнения (это почти наверняка одна из причин, если не причина, почему Linux проверяет на инструкция по загрузке на IA-32HLT- совместимые процессоры и, вероятно, выполняет аналогичные проверки на других архитектурах), будучи уверенными в том, что при некотором разумном определении будущего времени сработает прерывание и будет вызван планировщик задач. Поскольку прерывание срабатывает независимо от того, какую другую работу выполняет ЦП (в этом и заключается идея прерываний), планировщик регулярно выполняется и получает возможность определить, какой поток должен быть выполнен в течение следующего отрезка времени. Поскольку переключение контекста относительно дорого, обычно возможно (по крайней мере, через исходный код) настроить агрессивность переключения планировщика между потоками; переключение потоков чаще приводит к тому, что система становится более отзывчивой, но накладные расходы на переключение означают, что общее время выполнения заданного набора задач больше. Самый быстрыйсистема будет переключаться между потоками только в том случае, если работающий поток больше не может быть запущен (это означает, что он заблокирован в ожидании чего-либо или завершил свою работу), поскольку это минимизирует издержки, тогда как наиболее отзывчивая система переключается между потоками каждый раз, когда вызывается планировщик, потому что это минимизирует среднее время ожидания, прежде чем конкретный поток получит процессорное время. Идеальная настройка обычно находится где-то посередине между этими двумя, и компромисс между этими вариантами, вероятно, является одной из главных причин, почему Linux предлагает выбор из нескольких планировщиков, а также некоторые параметры настройки через конфигурацию ядра.

С другой стороны, совместные многозадачные ОС и среды (например, Windows 3.x ) полагаются на каждое приложение, чтобы регулярно передавать управление планировщику. Обычно есть функция API, специально предназначенная для этого, и часто многие функции API делают это как часть своего внутреннего потока выполнения, потому что это помогает сделать взаимодействие с пользователем более плавным. Этот подход к проектированию работает хорошо до тех пор, пока все приложения хорошо себя ведут и уступают управление с короткими интервалами во время любых длительных операций (длительный означает более небольшой доли секунды), но приложение, которое не может засоряться вся система. Это одна из основных причин, почему Windows 3.x так плохо работала в тесте многозадачности, о котором я упоминал выше, в то время как OS / 2весело проводя время, выполняя одни и те же задачи на одном и том же оборудовании: приложение могло сказать дисководу гибких дисков записать определенный сектор, и время, которое потребовалось на это, прежде чем возвращенный вызов мог быть фактически измеримым (от десятков до сотен миллисекунд или Больше); система многозадачности с вытеснением может прервать работу планировщика при следующем запланированном вызове, заметить, что поток, который в данный момент «работает», фактически заблокирован вызовом write, и просто переключиться на другой поток, который работает. (На практике это немного сложнее, но это общая идея.)

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


11
Я люблю "пользовательский ввод, в частности, очень медленный"
Джон Дворжак

«Потоки», которыми обладает «процессор», - это число, которое он может выполнять одновременно в любой момент. Он переключается между активными потоками, предоставляя каждый оборот или долю ЦП на некоторое время, когда это возможно. Процессы / потоки, «заблокированные» или ожидающие ввода-вывода (такие как диск, ввод с клавиатуры / мыши и т. Д.) Или что-то еще (например, примитивы синхронизации, такие как мьютексы и т. Д.), Пропускают свой ход.
LawrenceC

1
Комментарии приятно просить разъяснений, но они не подходят для расширенного обсуждения, и в какой-то момент их трудно прочитать. Можете ли вы взять это вместо Super User Chat ? Спасибо.
slhck

1
@slhck Я создал комнату, но не смог найти способ перенести обсуждение в эти комментарии, что было бы неплохо. Это то, что вы можете сделать вручную в качестве модератора? chat.stackexchange.com/rooms/9547/…
CVn

1
К сожалению нет. Существует автоматический процесс миграции, который не может быть запущен вручную, но мы не можем переместить комментарии в чат-комнату. Мы оставим комментарии на некоторое время, но я бы посоветовал другим следить за обсуждением в чате, который вы создали.
Slhck

18

Подумайте о четырехполосном шоссе с 1037 автомобилями.

Ваша ОС нуждается в большом количестве запущенных процессов для работы с большим количеством сервисов. Даже самые простые графические программы потребуют многопоточного программирования. Когда вы думаете о множестве открытых программ, вы обнаруживаете необходимость совместного использования ресурсов вычислительной мощности.

Ваш менеджер задач показывает текущую загрузку системы. Спецификации вашего компа показывают, сколько потоков (во внешнем интерфейсе) принимается для параллельного выполнения. Без особой разницы между гиперпоточностью и многоядерными функциями, с более логичным принятием потоков внешнего интерфейса, система в целом будет работать лучше.


8
«Даже самые простые графические программы потребуют многопоточного программирования». Неправильно. Вполне возможно писать однопоточные приложения с графическим интерфейсом; вплоть до Windows 95, для всех намерений и целей каждый делал это таким образом. Это делает некоторые задачи более сложными (например, фоновая печать тривиальна с несколькими потоками, но, безусловно, нетривиальна в однопоточном приложении, особенно если вы также ограничены в памяти, как было тогда), но между ними есть огромная разница » X облегчается Y "и" X требует Y ".
CVn

8
@ MichaelKjörling: «вплоть до Windows 95, для всех намерений и целей каждый делал это так» * - правда? Даже на системах * nix, работающих под Motif в 80-х?
LarsH

@LarsH Хороший вопрос, и я подумал, что слишком поздно, чтобы редактировать его в комментарии. Но это не отменяет сути вопроса, а именно: совершенно возможно писать однопоточные приложения с графическим интерфейсом. Для этого вам не нужна многопоточность, хотя это значительно облегчает программисту некоторые задачи.
CVn

@ MichaelKjörling: Я согласен, это не отменяет вашу точку зрения, которая является действительной. (Я не думаю, что неправильное утверждение Упрего также отрицает его точку зрения.)
LarsH

В качестве примера того, что сказал @ MichaelKjörling, Visual Basic (до .NET) как язык программирования не поддерживал многопоточность. Все было запущено в одном потоке. Если вы хотите обработать пользовательский ввод в середине длительной операции, вы бы вызвали вызов DoEvents, который обработал бы очередь сообщений - но это было сделано в том же потоке и заблокировал бы эту длительную операцию, пока все сообщения не были обработаны , (Конечно, вы можете вызывать функции Win32 API и / или создавать дополнительные процессы, но в этот момент вы также можете использовать один из языков более низкого уровня.)
Боб

5

Мы должны сделать шаг назад и спросить себя: как компьютер с одним процессором может иметь два потока?

Потоки - это программные объекты, а не аппаратные. Чтобы иметь другой поток, вам просто нужна память для объектов, составляющих поток, таких как структура дескриптора и стек.

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

Из всех потоков, существующих в системе, только подмножество обычно находится в состоянии, которое обычно называется «работоспособным». Выполняемые потоки стремятся к запуску: они либо выполняются, либо находятся в «очереди выполнения», ожидая отправки планировщиком. Потоки, которые не могут быть запущены, «блокируются», ожидают получения какого-либо ресурса или получения ввода, или «спят», что похоже на блокировку на входе, где «ввод» - это ход времени. «Переключение контекста» происходит, когда функция планировщика в операционной системе просматривает очередь выполнения процессора и выбирает другой поток для выполнения.

Не путайте «гиперпоточность» , которая является названием Intel для определенной аппаратной функции.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.