Зелёные потоки ({yl~udy hkmktn)

Перейти к навигации Перейти к поиску

Зелёные потоки (англ. green threads) — потоки выполнения, управление которыми вместо операционной системы производит среда выполнения (например, JVM), эмулируя многопоточную среду вне зависимости от возможностей операционной системы по реализации встроенных или легковесных потоков. Управление зелёными потоками происходит в пользовательском пространстве, а не пространстве ядра, что позволяет им работать, в частности, в условиях отсутствия поддержки встроенных потоков[1].

На многоядерных процессорах реализация встроенных потоков (native threads) может автоматически назначать работу нескольким процессорам, в то время как реализация зелёных потоков обычно не может[1][2]. Зелёные потоки могут быть запущены гораздо быстрее в некоторых средах выполнения. Однако, на однопроцессорных компьютерах наиболее эффективная модель ещё не определена. Тесты на компьютерах под управлением (старого) Linux на ядре версии 2.2 показали[3]:

Когда зелёный поток выполняет блокирующий системный вызов, блокируется не только этот поток, но и все потоки внутри процесса[4]. Чтобы избежать этой проблемы, зелёные потоки должны использовать асинхронные операции ввода-вывода, хотя данную сложность можно скрыть, порождая скрытые для пользователя потоки на каждую операцию ввода-вывода, которые объединяются с зелёными потоками.

Есть также механизмы, которые позволяют использовать собственные потоки и снизить накладные расходы на активацию и синхронизацию потоков. В частности, пулы потоков снижают затраты на порождение новых потоков за счет повторного использования ограниченного числа потоков[5]. Кроме того, языки, исполняющиеся на виртуальных машинах, но при этом использующие встроенные потоки, могут использовать технику оптимизации — анализ побочных эффектов (Escape-анализ), чтобы избежать синхронизации блоков кода, когда это возможно[6].

Зелёные потоки в JVM

[править | править код]

В Java 1.1 green threads являлись единственной потоковой моделью (моделью распараллеливания потоков), используемой в JVM[7], по крайней мере, в Solaris. Ввиду того, что green threads обладают ограничениями в сравнении с native threads, в последующих версиях Java основной упор сделан на native threads.

Исключением является виртуальная машина Squawk, которая представляет собой смесь ОС для маломощных устройств и JVM. Она использует green threads для того, чтобы сохранить машинный код в абсолютном минимуме и поддерживать миграцию своих изолятов (isolates).

Зелёные потоки в других языках

[править | править код]

Есть и другие языки программирования, в которых по-прежнему аналоги green threads используются вместо native threads. Примеры:

  • CPython с greenlet, eventlet и gevent
  • Erlang
  • Go
  • Haskell
  • Limbo
  • Lua, использующая сопрограммы для параллелизма (эталонная реализация ограничивает их использование в коде Lua, но coco-расширение позволяет использовать истинную семантику сопрограмм в Си
  • Оккам
  • Ruby до версии 1.9
  • SML/NJ реализации Concurrent ML
  • Smalltalk
  • Stackless Python — поддерживает вытесняющую многозадачность или кооперативную многозадачность через микропотоки (так называемые тасклеты (tasklets))[8].
  • PHP с версии 8.1 поддерживает фиберы (англ. fibers.

Виртуальная машина Erlang имеет то, что можно назвать зелёными потоками — они как рабочие процессы системы, хоть и не объявляют состояние, как это делают потоки, но реализуются в рамках Erlang Run Time System (ERTS). Их иногда рассматривают в качестве «green threads», но они имеют существенные отличия от стандартных green threads.

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

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

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

[
   [(Delay forMilliseconds: 50) wait] repeat
] forkAt: Processor highIOPriority

Другие реализации, например, QKS Smalltalk, постоянно используют разделение времени. В отличие от большинства реализаций green threads, QKS Smalltalk имеет поддержку предотвращения инверсии приоритетов.

Примечания

[править | править код]
  1. 1 2 Four for the ages. Архивировано 6 февраля 2013 года.
  2. What is the difference between "green" threads and "native" threads? Архивировано 6 февраля 2013 года.
  3. Comparative performance evaluation of Java threads for embedded applications: Linux Thread vs. Green Thread [1] Архивная копия от 16 октября 2012 на Wayback Machine
  4. Stallings, William. Operating Systems, Internal and Design Principles (англ.). — New Jersey: Prentice Hall, 2008. — P. 171. — ISBN 9780136006329.
  5. Concurrency in JRuby. Дата обращения: 29 января 2013. Архивировано из оригинала 30 января 2014 года.
  6. Java theory and practice: Synchronization optimizations in Mustang. Архивировано 6 февраля 2013 года.
  7. Threading. Архивировано 6 февраля 2013 года.
  8. Stackless.com: About Stackless. Архивировано 6 февраля 2013 года.