Это две фразы, которые описывают одно и то же с (очень немного) разных точек зрения. Параллельное программирование описывает ситуацию с точки зрения аппаратного обеспечения - по крайней мере два процессора (возможно, в одном физическом пакете) работают над проблемой параллельно. Параллельное программирование описывает вещи больше с точки зрения программного обеспечения - два или более действия могут происходить в одно и то же время (одновременно).
Проблема здесь в том, что люди пытаются использовать две фразы, чтобы провести четкое различие, когда ни одна из них не существует. Реальность такова, что разделительная линия, которую они пытаются провести, была нечеткой и нечеткой в течение десятилетий, а со временем становилась все более нечеткой.
Они пытаются обсудить тот факт, что когда-то на большинстве компьютеров был только один процессор. Когда вы выполняли несколько процессов (или потоков) на одном и том же ЦП, ЦП действительно выполнял только одну инструкцию из одного из этих потоков за раз. Появление параллелизма было иллюзией - процессор переключался между выполнением инструкций из разных потоков достаточно быстро, чтобы для человеческого восприятия (для которого что-то менее 100 мсек или около того выглядит мгновенно) казалось, что он делал много вещей одновременно.
Очевидная противоположность этому - это компьютер с несколькими ЦП или ЦП с несколькими ядрами, поэтому машина выполняет инструкции из нескольких потоков и / или процессов в одно и то же время; выполнение кода не может / не имеет никакого влияния на выполнение кода в другом.
Теперь проблема: такого четкого различия почти никогда не было. Компьютерные дизайнеры на самом деле довольно умны, поэтому они давно заметили, что (например), когда вам нужно было прочитать некоторые данные с устройства ввода-вывода, например с диска, потребовалось много времени (с точки зрения циклов ЦП), чтобы финиш. Вместо того, чтобы оставить процессор бездействующим, когда это произошло, они нашли различные способы позволить одному процессу / потоку сделать запрос ввода-вывода и позволить коду из какого-то другого процесса / потока выполняться на процессоре, пока запрос ввода-вывода завершен.
Итак, задолго до того, как многоядерные процессоры стали нормой, у нас были параллельные операции из нескольких потоков.
Это только верхушка айсберга. Несколько десятилетий назад компьютеры начали обеспечивать еще один уровень параллелизма. Опять же, будучи достаточно умными людьми, компьютерные дизайнеры заметили, что во многих случаях у них были инструкции, которые не влияли друг на друга, поэтому можно было выполнять более одной инструкции из одного и того же потока одновременно. Одним из первых примеров, который стал довольно известным, были Control Data 6600. Это был (с довольно большим отрывом) самый быстрый компьютер в мире, когда он был представлен в 1964 году - и большая часть той же базовой архитектуры остается в использовании сегодня. Он отслеживал ресурсы, используемые каждой инструкцией, и имел набор исполнительных блоков, которые выполняли инструкции, как только стали доступны ресурсы, от которых они зависели, очень похоже на конструкцию самых последних процессоров Intel / AMD.
Но (как говаривали рекламные ролики) подождите - это еще не все. Есть еще один элемент дизайна, чтобы добавить еще больше путаницы. Ему было дано довольно много разных имен (например, «Hyperthreading», «SMT», «CMP»), но все они ссылаются на одну и ту же основную идею: процессор, который может выполнять несколько потоков одновременно, используя комбинацию некоторых ресурсов, которые являются независимыми для каждого потока и некоторых ресурсов, которые совместно используются потоками. В типичном случае это сочетается с описанным выше параллелизмом на уровне команд. Для этого у нас есть два (или более) набора архитектурных регистров. Затем у нас есть набор исполнительных блоков, которые могут выполнять инструкции, как только становятся доступными необходимые ресурсы.
Тогда, конечно, мы перейдем к современным системам с несколькими ядрами. Здесь все очевидно, верно? У нас есть N (где-то между 2 и 256 или около того, в настоящий момент) отдельных ядер, которые могут выполнять все команды одновременно, поэтому у нас есть четкий случай реального параллелизма - выполнение инструкций в одном процессе / потоке не ' не влияет на выполнение инструкций в другом.
Ну вроде. Даже здесь у нас есть некоторые независимые ресурсы (регистры, исполнительные блоки, по крайней мере, один уровень кеша) и некоторые общие ресурсы (обычно, по крайней мере, самый низкий уровень кеша, и определенно контроллеры памяти и пропускная способность для памяти).
Подводя итог: простые сценарии, которым люди любят противопоставлять общие ресурсы и независимые ресурсы, практически никогда не бывают в реальной жизни. Располагая всеми ресурсами, мы получаем что-то вроде MS-DOS, где мы можем запускать только одну программу за раз, и нам нужно прекратить запускать одну, прежде чем мы сможем запустить другую. Имея полностью независимые ресурсы, у нас есть N компьютеров, работающих под управлением MS-DOS (даже без сети для их подключения), и у них нет возможности вообще что-либо делить между ними (потому что, если мы даже можем поделиться файлом, то это общий ресурс, нарушение основной предпосылки, что ничто не передается).
Каждый интересный случай включает в себя некоторую комбинацию независимых ресурсов и общих ресурсов. Каждый достаточно современный компьютер (и многие другие, которые совсем не современны) обладают, по крайней мере, некоторой способностью выполнять, по крайней мере, несколько независимых операций одновременно, и почти что-либо более сложное, чем MS-DOS, воспользовалось этим, чтобы, по крайней мере, в некоторой степени.
Хорошего, четкого разделения между «параллельным» и «параллельным», которое люди любят рисовать, просто не существует, и почти никогда не существует. То, что люди любят классифицировать как «параллельные», обычно все еще включает, по крайней мере, один, а часто и более разные типы параллельного выполнения. То, что им нравится классифицировать как «параллельные», часто включает в себя совместное использование ресурсов и (например) один процесс, блокирующий выполнение другого, при использовании ресурса, который совместно используется этими двумя.
Люди, пытающиеся провести четкое различие между «параллельным» и «параллельным», живут в фантазии компьютеров, которых на самом деле никогда не существовало.