goroutine vs thread

Язык программирования Go использует goroutine-ы также как языки C++ и Java используют потоки. Но есть и существенные отличия.  Для понимания их нужно рассмотреть, как goroutine используют память, как создаются или уничтожаются, как происходит переключение выполнения, как используются процессоры.

Использование памяти.

Создание goroutine не требовательно к памяти - достаточно всего 2 КБ в стеке.  В случае же запуска потока требуется более 1 МБ памяти, что в 500 раз больше. Если у вас есть сервер подключений, то в случае входящих соединений Вы можете смело создавать по одной goroutine на коннект и жить спокойно. Если вы примените такой подход с  потоками, не ограничив их число сверху, то вы рискуете получить ошибку OutOfMemoryError.

Переключение между задачами

В случае когда выполнение одного потока должно быть прервано система автоматически сохраняет значения всех регистров в стек (16 основных регистров, указатель на верхушку стека, счетчик программ, XMM регистры, состояние сопроцессора, AXV регистры и др). Что может быть существенно в некоторых ситуациях.

В случае goroutine для переключениям между ними достаточно сохранить верхушку стека, счетчик программ и регистр DX, что значительно эффективнее.

Выполнение goroutine

Для выполнения goroutine системой создается несколько потоков, которые и будут обслуживать все goroutine приложения. В каждый момент времени такой процесс обрабатывает только одну goroutine. В случае, если будет выполнена блокировка goroutine, выполняющий поток переключится на выполнение следующей goroutine.

Исходя из того, что goroutine выполняются согласованно, то существует вероятность, что одна из них может зациклится и тем самым прервать выполнение других goroutine в текущем потоке, что имело место до версии 1.2 . Сейчас в случае, если goroutine входит в бесконечный цикл, не содержащий функций, то она может быть выгружена.

Прерывания

Прерывания выполнения goroutine производится в случае, когда:

  • ожидается сетевой ввод
  • когда выполнение приостанавливается на заданое время (sleep)
  • в случае операций с каналами
  • в случае использования примитивов синхронизации из пакета  sync

Таким образом, если в системе запущены десятки тысяч goroutine то они практически не требуют системных ресурсов, так как основная масса из них находится в режиме прерывания выполнения.

goroutine можно рассматривать как легковесную абстракцию на стандартными системными потоками.

Потоки и процессоры

В большинстве случае программисту на Go не приходится задумываться о том, сколько системных потоков обслуживают goroutine-ы его приложения. Но тем не менее в языке Go есть возможность явным образом задать число ядер, которые будут обслуживать его приложение, для оеспечения максимальной производительности. Это делается путем вызова:

runtime.GOMAXPROCS(n)

Разделяемые ресурсы

В большинстве случаев на практике приходится работать с разделяемыми ресурсами, доступ к которым имеют более чем одна goroutine. Для обеспечения доступа к ним можно использовать пакет sync.  Для обеспечения передачи данных между goroutine лучшей практикой считается использование каналов.

 

Тэги: go golang программирование


 

Комментарии

JoshuaEnazy • 13.06.2017 07:17
Спасибо за статью, узнал много нового

 


 
архив

подписка