Как реализовать несколько «потоков», работающих только в одном потоке - PullRequest
8 голосов
/ 23 марта 2011

В последнее время я размышлял: как реализовать несколько «потоков» только в одном потоке?

Я имею в виду, как они реализуют несколько параллельно работающих фрагментов кода только в одном потоке? Как они сохраняют состояние «потока», создают прерывание и передают ЦП следующему?

Я думаю, что актеры Scala это реализуют. Но как?

Это может быть ответом для JVM или C, это не имеет значения. Я просто очень хочу изучить теорию этого.

Ответы [ 6 ]

6 голосов
/ 23 марта 2011

Я думаю, что вы путаете сопрограммы и зеленые темы здесь.

Сопрограммы отказываются от контроля, когда они готовы сделать это, без какого-либо перерыва, поэтому вопрос о прерывании здесь не имеет значения. Актеры Scala реализованы как сопрограммы.

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

4 голосов
/ 23 марта 2011

С актерами все просто: вместо одного потока на одного актера вы используете один и тот же поток для выполнения сообщений для нескольких акторов.Однако, если субъект выполняет блокирующий вызов или сложные вычисления, для выполнения сообщений в других субъектах должен использоваться другой поток.

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

Другое решение - использовать продолжения, реализованные в компиляторе Scala.Прерывание и возобновление выполнения затем обрабатываются на уровне байт-кода JVM, где локальное состояние сохраняется и восстанавливается.Поддержка VM не требуется.

3 голосов
/ 23 марта 2011

Вы имеете в виду как задачи в ExecutorService или ScheduledExecutorService в Java?

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

Если вы хотите узнать больше информации, вам может быть интересно прочитать код.

2 голосов
/ 23 марта 2011

Библиотека Akka - действительно хорошая реализация модели актеров. У него довольно хороший прямой Java API (в дополнение к Scala), и документ довольно хорош .

2 голосов
/ 23 марта 2011

Использование сопрограмм

1 голос
/ 23 марта 2011

Один из способов сделать это - зарегистрировать пакет потоков в коде пользователя для какого-либо прерывания по таймеру от ядра.Всякий раз, когда он получает такое прерывание, он может сказать ядру прекратить выполнение всех потоков ядра, которые сами запускают несколько разных потоков.Для каждого из этих потоков код прерывания таймера может проверять стек на наличие этих потоков, записывать важную информацию (регистры, указатель стека, счетчик программ и т. Д.) Во вспомогательном месте, а затем загружать сохраненную информацию для другого из смоделированногопотоки, работающие на этом фактическом потоке.Затем он может возобновить поток ядра, на котором выполняется смоделированный поток.Таким образом, вы можете симулировать переключение контекста между несколькими потоками, работающими в одном потоке ядра.

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

...