Первой версией была многопроцессорная система: у вас была бы одна или несколько материнских плат с одним или несколькими чипами ЦП. Основная проблема здесь заключалась в том, что процессоры должны были бы предоставлять некоторые из своих внутренних данных другому процессору, чтобы они не мешали им.
Следующим шагом была гиперпоточность. Один чип на материнской плате, но у него было два внутренних компонента, поэтому он мог выполнять две инструкции одновременно.
Текущая разработка - многоядерная. По сути, это оригинальная идея (несколько законченных процессоров), но в одном чипе. Преимущество: разработчики микросхем могут легко вставить дополнительные провода для сигналов синхронизации в микросхему (вместо того, чтобы прокладывать их через штырь, затем через переполненную материнскую плату и во второй кристалл).
Сегодня суперкомпьютеры многоядерные, многоядерные: у них много материнских плат с обычно 2-4 процессорами на них, каждый процессор многоядерный и каждый имеет свою собственную оперативную память.
[EDIT] Вы в значительной степени правильно поняли. Всего несколько мелких замечаний:
Гиперпоточность отслеживает сразу два контекста в одном ядре, обеспечивая больший параллелизм для вышедшего из строя ядра ЦП. Благодаря этому исполнительные блоки загружаются работой, даже когда один поток останавливается из-за промаха в кэше, неправильного предсказания ветвления или ожидания результатов от инструкций с высокой задержкой. Это способ увеличить общую пропускную способность без репликации большого количества оборудования, но во всяком случае он замедляет каждый поток в отдельности. См. Эти вопросы и ответы для получения более подробной информации и объяснения того, что было не так в предыдущей формулировке этого абзаца.
Основная проблема с несколькими процессорами заключается в том, что код, выполняющийся на них, в конечном итоге получит доступ к ОЗУ. Есть N процессоров, но только одна шина для доступа к ОЗУ. Таким образом, у вас должно быть какое-то оборудование, которое гарантирует, что а) каждый ЦП получает достаточный объем доступа к ОЗУ, б) доступ к одной и той же части ОЗУ не вызывает проблем и в) что наиболее важно, что ЦП 2 будет уведомлен когда ЦП 1 записывает в некоторый адрес памяти, который ЦП 2 имеет во внутреннем кэше. Если этого не произойдет, ЦП 2 с радостью будет использовать кешированное значение, не обращая внимания на то, что оно устарело.
Представьте, что у вас есть задачи в списке, и вы хотите распределить их по всем доступным процессорам. Таким образом, CPU 1 выберет первый элемент из списка и обновит указатели. CPU 2 сделает то же самое. Из соображений эффективности оба процессора будут копировать в кэш не только несколько байтов, но и целую «строку кэша» (какой бы она ни была). Предполагается, что когда вы читаете байт X, вы скоро также прочитаете X + 1.
Теперь у обоих процессоров есть копия памяти в кэше. Затем ЦП 1 выберет следующий элемент из списка. Без синхронизации кеша он не заметил бы, что ЦП 2 тоже изменил список, и он начнет работать с тем же элементом, что и ЦП 2.
Это то, что действительно делает многопроцессорными. Побочные эффекты этого могут привести к снижению производительности по сравнению с тем, что вы получили бы, если бы весь код выполнялся только на одном процессоре. Решение было многоядерным: вы можете легко добавить столько проводов, сколько вам нужно для синхронизации кешей; вы даже можете копировать данные из одного кеша в другой (обновляя части строки кеша без необходимости сбрасывать и перезагружать его) и т. д. Или логика кеширования может гарантировать, что все процессоры получат одну и ту же строку кеша, когда они обращаются к одной и той же части реальная оперативная память, просто блокируя ЦП 2 на несколько наносекунд, пока ЦП 1 не внесет свои изменения.
[EDIT2] Основная причина, по которой многоядерный процессор проще, чем многопроцессорный, заключается в том, что на материнской плате вы просто не можете проложить все провода между двумя чипами, которые вам понадобятся для обеспечения эффективной синхронизации. Кроме того, сигнал распространяется только на 30 см / нс (скорость света; в проводе обычно намного меньше). И не забывайте, что на многослойной плате сигналы начинают влиять друг на друга (перекрестные помехи). Нам нравится думать, что 0 - это 0 В, а 1 - 5 В, но на самом деле «0» - это что-то между -0,5 В (перегрузка при падении линии с 1-> 0) и 0,5 В, а «1» - это что-то выше 0,8 В.
Если у вас все внутри одного чипа, сигналы работают намного быстрее, и вы можете иметь их сколько угодно (ну, почти :). Кроме того, намного легче контролировать перекрестные помехи.