@equentor

Несколько вопросов про параллельные вычисления?

Пишу на PHP, решил попробовать NodeJS. Прочитал про EventLoop, и невольно начал углубляться в тему параллельного выполнения. По ходу дела возникло несколько вопросов.
На сколько я понял, количество потоков выполнения, которые процессор может обработать в единицу времени ограничиваются количеством ядер процессора, так 1 вычислительное ядро (суть - процессор) = возможности обработать 1 поток выполнения. Отсюда вывод что 1-ядерный процессор в принципе не способен делать несколько операций параллельно, но он вычисляет на столько быстро, что человеку кажется что программы работают параллельно, без прерываний. 2-ядерный - 2 реально параллельные операции и т.д.
Если у нас 8-ми ядерный процессор, то он может обрабатывать 8 потоков по-настоящему параллельно. Не берём во внимание hypertrading, т.к. процессор с гипертрейдингом не даёт линейного прироста производительности, а лишь даёт возможность одному ядру якобы обрабатывать 2 потока (делит 1 ядро на 2 логических ядра). Якобы - потому-что не полноценно, 1 виртуальный поток просто получает возможность использовать вычислительные ресурсы ядра которые находятся в простое во время выполнения второго виртуального потока. Всё-же получается некоторая конкуренция, но всё-же semi-параллельно, скажем так.

А теперь абсолютно идиотские вопросы:
1. Допустим у моего компьютера 4 ядра, на нём стоит операционная система, в операционной системе запущенно множество служб, прикладных программ и т.д. Каждая служба/программа создаёт процесс. Одновременно в системе запущено множество процессов (можно увидеть в диспетчере задач на винде или через какой-нибудь htop или ps на линуксе) и тут я решил написать свою программу, которая бы делала действительно параллельные вычисления. По логике - она должна полностью занять как минимум 2 ядра, что-бы делать несколько операций по-настоящему параллельно. Но ведь в системе уже крутится куча всего что занимает ядра. Снова конкуренция и переключение? Значит, никакой реальной параллельности?

2. Некоторые языки программирования поддерживают многопоточность. Приложение при запуске создаёт процесс, который может создавать внутри себя потоки. Для каждого процесса выделяется своя область памяти, потоки внутри процесса могут обращаться к этой памяти. Что, если мы создали потоков больше чем у нас есть физических ядер? Куда деваются потоки, которым не хватило ядер? А что если нет полностью свободных ядер? Это ведь снова переключения выполнения?

3. Асинхронность - тоже видимость реально параллельного выполнения?

4. У нас есть тяжёлая задача которую процессор мог бы выполнить за (например) 10 секунд, мы создаём 2 потока и делим между ними задачу, у нас, например 2 ядра в процессоре. 1 поток ложится на 1, второй на 2? А если 1 ядро занято (какой нибудь системной утилитой или службой, пусть даже на 1%), то оба потока выполняются на 1 ядре, тогда каждый поток будет по 5 секунд, а поочерёдно это снова 10, т.е. мы не ускорили вычисления? Получается, снова поочерёдное переключение с большой скоростью (тактовой частотой)?

Я н.н.п. Прошу, внесите ясности. Может быть ссылки на почитать информацию в структурированном виде? На C/ASM не писал, рассуждения чисто теоретические.
  • Вопрос задан
  • 252 просмотра
Решения вопроса 1
@eldog
C#/C++/SQL разработчик, Microsoft stack
1. > Снова конкуренция и переключение? Значит, никакой реальной параллельности?
Да, переключение. Но почему же нет параллельности? Допустим, один ваш интенсивный поток займёт 95% одного ядра, другой 80% другого. Параллельность.

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

2. > А что если нет полностью свободных ядер? Это ведь снова переключения выполнения?
Да, конечно, переключение. В зависимости от языка программирования и системы исполнения, потоки могут даже выполняться из пула, и если пул разобрали, то потом вообще будут ждать, независимо от загрузки ядер.

3. Асинхронность зависит от реализации. Чаще всего это тоже многопоточность, см. выше.

4. Если у вас два ядра, одно свободно, другое занято на 1%, потоки тяжёлые, им нужна вся производительность, которая есть, то можно предположить, что ваши тяжелые потоки будут выполняться на разных ядрах. Что занято на 1%, то свободно на 99% :-) Но создание потока требует времени и ресурсов, это не бесплатно. Поэтому в сугубо гипотетической ситуации, когда потоков много, загрузка большая, а ядер мало, создание лишних потоков может не ускорить, а замедлить исполнение, да. Это одна из причин, почему существуют пулы потоков, как в .net, например. Создаём столько потоков, сколько разумно, остальные ждут.

В целом, не стоит так беспокоиться насчёт "переключения". Планировщик задач крутится всегда, даже если у вас есть полно свободных ядер, переключение это неотъемлемая часть системы.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@insighter
Поток потоку рознь. Можно создать поток, который вот прям сейчас архив распаковывает и тут да, может получится что ОС будет буквально "отбирать" у него процессорное время чтобы дать поработать другим задачам.

А можно создать поток который лениво TCP порт прослушивает и толком ничего не делает, и как то жирно отдавать всё процессорное ядро для таких вещей.

4) Максимальное ускорение вы получите максимальным кол-вом ядер. Просто ОС за вас берет заботу чтобы созданные приложением 8 потоков корректно работали и на 8-ми ядерном процессоре и на 2-х ядерном.
Ответ написан
saboteur_kiev
@saboteur_kiev Куратор тега Программирование
software engineer
Читайте как работает шедулер в вашем операционной системе, тот который управляет многозадачностью в операционной системе.

Нужно понимать, что многозадачность обеспечивает не количество ядер, а именно операционная система - многозадачность существовала еще при одном одноядерном процессоре.

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

Как бы вы не рассчитывали кол-во процессов и ядер, всегда будут переключения. Но если потоков бОльше, чем ядер - это не приводит к ускорению вычислений.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы