Зарегистрируйтесь, чтобы продолжить обучение

Многоядерность и параллелизм Основы ЭВМ

Современный процессор устроен так, что внутри него есть несколько физических ядер. Ядро (Core) — это реальный вычислительный блок с регистрами, кэшами, арифметико-логическим устройством (ALU, Arithmetic Logic Unit). Одно ядро может исполнять инструкции независимо от других, и именно количество ядер определяет, сколько задач реально можно выполнять параллельно. Если в системе восемь ядер, значит восемь независимых потоков команд могут выполняться одновременно без взаимного ожидания.

Кроме физических ядер существуют потоки. Поток (Thread, ещё называют Logical Processor или Hardware Thread) — это логический исполнитель внутри одного ядра. Когда включена технология SMT (Simultaneous Multithreading), у Intel известная как HyperThreading (HT), одно ядро «раздваивается» и показывает себя операционной системе как два логических CPU. ОС думает, что процессоров больше, чем есть на самом деле. Смысл в том, что ядро может загружаться эффективнее: если один поток простаивает и ждёт данные из памяти, второй использует свободные вычислительные блоки. Но это не удваивает мощность: если оба потока выполняют тяжёлые вычисления, они делят одни и те же ресурсы и прироста почти нет.

Работа с множеством процессов сразу создаёт проблемы с контекстом. Контекстное переключение (Context Switch) — это момент, когда операционная система приостанавливает выполнение одного процесса и передаёт управление другому. Для этого нужно сохранить всё текущее состояние первого процесса: значения регистров, счётчик инструкций, указатели стека. Затем ОС загружает сохранённое состояние второго процесса и запускает его на том же ядре.

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

В многопроцессорных системах добавляется проблема когерентности (Cache Coherency). У каждого ядра есть свои кэши L1 и L2, и одно и то же значение может храниться в нескольких копиях. Когда одно ядро изменяет переменную, остальные должны получить обновлённое значение. Для этого процессор использует протоколы когерентности, самый распространённый — MESI (Modified, Exclusive, Shared, Invalid), который рассылкой сигналов заставляет кэши синхронизироваться. При большом числе потоков и частых изменениях данных это превращается в нагрузку на шину и снижает масштабируемость приложений.

Синхронизация (Synchronization) между потоками становится ещё одним ограничением. Если несколько потоков обращаются к одному ресурсу, например к очереди задач или строке в таблице базы данных, они должны использовать блокировки (Locks или Mutexes). Пока один поток держит замок, остальные ждут. При высокой конкуренции это превращает параллельность в последовательное выполнение: ядра простаивают, нагрузка растёт, а сервис работает медленнее.

В результате видно, что физические ядра (Cores) дают реальный параллелизм, а потоки (Threads) через SMT позволяют лучше использовать простаивающие ресурсы, но не делают ядро в два раза мощнее. Контекстные переключения (Context Switches) тратят время и обнуляют кэш, когерентность (Cache Coherency) нагружает систему при совместном доступе, а синхронизация (Synchronization) может полностью убрать преимущество от многопоточности. Поэтому высокая загрузка CPU в графиках не всегда означает реальную скорость: часто это показатель того, что процессор занят ожиданием памяти (Memory Latency) и согласованием работы потоков.

Человек работает за компьютером, открывает одну вкладку за другой, пока их не становится сотня. Каждая вкладка — это отдельная задача для компьютера. Процессор имеет восемь ядер, с HyperThreading их видно как шестнадцать, но задач всё равно в несколько раз больше. Операционная система начинает тасовать вкладки по кругу: чуть-чуть работает одна, потом её откладывают, берут другую, потом третью, потом снова возвращаются к первой.

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

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

Снаружи видно только одно: процессор загружен на сто процентов, ноутбук шумит, вкладки открываются медленно и всё начинает подтормаживать.

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff