Это объяснение для новичка.
Это не технически точно, но ИМХО не так далеко от него, что любой человек получает урон от его чтения.
Он обеспечивает вход в понимание условий параллельной обработки.
Темы, задачи и процессы
Важно знать разницу между потоками и процессами. По умолчанию, начиная с нового процесса, выделяет выделенную память для этого процесса. Поэтому они обмениваются памятью без каких-либо других процессов и могут (теоретически) работать на отдельных компьютерах. (Вы можете обмениваться памятью с другими процессами, через операционную систему или «разделяемую память», но вы должны добавить эти функции, они по умолчанию недоступны для вашего процесса)
Наличие нескольких ядер означает, что каждый из них работает процесс может выполняться на любом незанятом ядре. Итак, в основном одна программа работает на одном ядре, другая программа работает на втором ядре, а фоновое обслуживание делает что-то для вас, работает на третьем (и т. Д. И т. Д.).
Нити - это что-то другое. Например, все процессы будут выполняться в основном потоке. Операционная система реализует планировщик, который должен выделять время процессора для программ. В принципе он скажет:
- Программа A, получите 0.01 секунды, чем пауза!
- Программа B, получить 0,01 секунды, затем приостановить!
- Программа A, получить 0,01 секунды, затем приостановить!
- Программа B, получить 0,01 секунды, затем приостановить!
вы получите идею ..
планировщик обычно может расставить приоритеты между потоками, поэтому некоторые программы получают больше процессорного времени, чем другие.
Планировщик может, конечно, планировать потоки на всех ядрах, но если он делает это в рамках процесса (разбивает потоки процесса на несколько ядер), то может наблюдаться снижение производительности, так как каждое ядро хранит собственный очень быстрый кеш памяти. Поскольку потоки одного и того же процесса могут обращаться к одному и тому же кешу, обмен памяти между потоками происходит довольно быстро.
Доступ к другому кешу ядра не так быстр, (даже если это возможно без прохождения через ОЗУ), поэтому в общем планировщике не будет разбиваться процесс на несколько ядер. В результате все потоки, относящиеся к процессу, работают на одном ядре.
| Core 1 | Core 2 | Core 3 |
| Process A, Thread 1 | Process C, Thread 1 | Process F, Thread 1|
| Process A, Thread 2 | Process D, Thread 1 | Process F, Thread 2|
| Process B, Thread 1 | Process E, Thread 1 | Process F, Thread 3|
| Process A, Thread 1 | Process C, Thread 1 | Process F, Thread 1|
| Process A, Thread 2 | Process D, Thread 1 | Process F, Thread 2|
| Process B, Thread 1 | Process E, Thread 1 | Process F, Thread 3|
Процесс может порождать несколько потоков, все они имеют родителя нитей области памяти, и обычно все работают на ядре, что родительский был запущен.
Имеет смысл порождать потоки в процессе, если у вас есть приложение, которое должно отвечать на то, что не может контролировать время. I.E. пользователи нажимают кнопку отмены или пытаются переместить окно, в то время как приложение выполняет расчеты, которые занимают много времени.
Отзывчивость пользовательского интерфейса требует, чтобы приложение проводило время на чтение и обработку того, что пользователь пытается сделать. Это может быть достигнуто в основном цикле, если программа выполняет части вычисления на каждой итерации. Тем не менее, это сложно сделать быстро, поэтому вместо кода вычисления выйдите из центра вычислений, чтобы проверить пользовательский интерфейс и обновить интерфейс, а затем продолжить. Вы запускаете код вычисления в другом потоке. Затем планировщик следит за тем, чтобы поток пользовательского интерфейса и поток вычислений получали процессорное время, поэтому пользовательский интерфейс реагирует на ввод пользователя, а расчет продолжается. И ваш код остается довольно простым.
Но я хочу, чтобы запустить мои расчеты другого ядра, чтобы набрать скорость
Для распределения вычислений на нескольких ядрах, вы могли бы породить новый процесс для каждого задания расчета. Таким образом, планировщик будет знать, что каждый процесс получает свою собственную память, и его можно легко запустить на незанятом ядре.
Однако у вас есть проблема, вам нужно поделиться памятью с другим процессом, чтобы он знал, что делать. Простой способ сделать это - обмен файлами через файловую систему. Вы можете создать файл с данными для расчета, а затем создать поток, управляющий выполнением (и связью) с другой программой (так что ваш пользовательский интерфейс реагирует, пока мы ждем результатов). Управляющий поток запускает другую программу с помощью системных команд, которая запускает ее как другой процесс. Другая программа будет записана так, что она будет работать с входным файлом в качестве входного аргумента, поэтому мы можем запускать ее в нескольких экземплярах в разных файлах. Если сама программа завершается, когда она завершена, и создает выходной файл, он может запускаться на любом ядре (или нескольких), и ваш процесс может читать выходной файл.
Это действительно работает, и если расчет займет много времени (например, много минут), это, возможно, нормально, хотя мы используем файлы для связи между нашими процессами.
Для расчетов, которые занимают всего несколько секунд, файловая система работает медленно, и ее ожидание почти удалит полученную производительность при использовании процессов вместо использования потоков. Поэтому в реальной жизни используется другое более эффективное использование памяти. Например, создание области общей памяти в ОЗУ.
«Создавать управляющую нить и подпроцесс порождения, разрешать связь с процессом через управляющий поток, собирать данные, когда процесс завершен, и раскрывать через управляющий поток» может быть реализован несколькими способами.
Задачи Ну «задачи» неоднозначны.
В целом это означает «Процесс или поток, который решает задачу».
Однако, на некоторых языках, таких как C#, это то, что реализует нить , например, что планировщик может рассматривать как процесс. Другие языки, которые предоставляют подобную функцию, обычно дублируют это либо задачи, либо рабочие.
Таким образом, с работниками/задачами он появляется программисту, как если бы это был просто поток, который можно легко обменивать память через ссылки и управлять, как и любой другой поток, путем вызова методов в потоке.
Но он представляется планировщику, как если бы это процесс, который можно запускать на любом ядре. Он реализует проблему с общей памятью довольно эффективно, как часть языка, поэтому программисту не придется повторно изобретать это колесо для всех задач.
Это часто упоминается как «Гибридная резьба» или просто «параллельные нити»
Какова ваша платформа? –
Этот «аппаратный параллелизм моего ноутбука 4» не гарантирует, что потоки будут работать на 4 отдельных ядрах. –
@ n.m Я использую mac, который имеет два ядра. – Q123