Процессы, потоки и виртуальные потоки
Что это?
C появлением многозадачности и многопоточности почти сразу начали существовать и три сущности: процессы, потоки и виртуальные потоки (корутины/горутины/файберы/etc). Что же каждая из них означает?
Процесс – это сущность операционной системы, которая по сути представляет вашу программу. Её отличительная черта в том, что эта сущность изолирована от других процессов и ничего о них не знает. По сути процесс может “представлять”, будто работает со своим виртуальным компьютером: у него есть своя память, и операционная система гарантирует, что эта память не будет сломана кем-то ещё; у него есть своё процессорное время, и операционная система опять же гарантирует, что инструкции процесса будут выполнены. Даже если ОС в процессе исполнения процесса передаст обработку другому процессу, а этот усыпит, то сам процесс может быть уверен, что это произойдёт прозрачно.
Тред (поток) – это уже часть процесса, которая позволяет ему определить несколько задач, которые должны исполняться вместе. То есть это те самые “задачи” во время “многозадачности”, и тут опять же операционная система отвечает за справедливое распределение времени между тредами, то есть ресурсы процессора вновь распределяются планировщиком операционной системы. И важное отличие тут от процессов – то что треды одного процесса делят общее адресное пространство, и разработчику уже нужно думать о том, как избежать одновременной записи в одну и ту же ячейку памяти, например, появляется необходимость в синхронизации. По сути ОС говорит тут тредам процесса: “вот ваш виртуальный компьютер, делайте с ним что хотите. Но если полезете за пределы своего адресного пространства, то будете наказаны”.
Виртуальный тред – очень похож на обычный тред, но это уже часть вашего кода с некоторыми особенностями. Здесь уже не операционная система отвечает за выделение процессорного времени, а ваша программа. Под программой я имею ввиду не только ваш код, но и рантайм, фреймворк или виртуальную JVM или .NET машину, которую вы используете (что можно считать частью кода вашей программы).
Для чего виртуальные треды нужны? Дело в том, что операционная система ничего не знает о вашем конечном коде и что вы делаете. Она ожидает, что вы делаете в каждом треде какую-то работу, что-то вычисляете, и честно распределяет имеющиеся ресурсы. А вы вот знаете, что в данный момент времени ничего полезного не делаете: вы ждёте разблокировки мьютекса, ответа сервера (IO) или чего-то ещё, и по сути вас можно просто снять с процессора до какого-то момента. Вы разными способами сообщаете это своему планировщику, и он уже решает, что делать с вами и ресурсами.
Стоит также упомянуть, что затраты на “спавн” каждой сущности отличаются: процессы и треды создаются через “syscall” – системный вызов к ядру ОС. Это сравнительно долго и дорого, особенно учитывая то, что процесс нужно добавить в таблицу процессов, подготовить ему виртуальное адресное пространства и так далее. Треду же нужно подготовить свой отдельный стек (чтобы к нему можно было вернуться), и он тоже выделяется бОльшим, в сравнении с виртуальными тредами.
А вот эти виртуальные треды (они же файберы, они же горутины, они же корутины) – это уже исключительно ответственность вашей программы, которая в распоряжении имеет N-ое количество системных тредов.
Что выбрать?
Зависит, очевидно, от задачи.
Если вам нужно разделить процессы по своим адресным пространствам, чтобы их изолировать или чтобы сэкономить время на синхронизации, и взаимодействия между процессами минимум, то выбираете процессы. Например, так работает веб-сервер nginx, или, если не ошибаюсь, режим балансировки в нодовском pm2
, когда он форкает ваш сервер по нескольким процессам. Но, конечно, количество этих процессов должно быть ограничено.
В остальных случаях треды и виртуальные треды. Виртуальные будут особенно важны, когда вам нужно быстро обработать много запросов, потому что намного дешевле, чем системные треды.
И я не зря выделил слово “нужно” – всегда стоит осознанно подходить к выбору чего-либо. Очевидно, масштабироваться процессами будет сложнее, чем просто наплодить тредов, и если вам кажется, что это даст лучший результат просто “потому что процессы”, то скорее всего не даст. Но при этом не бойтесь экспериментировать, если проект позволяет!;)