Share This
Связаться со мной
Крути в низ
Categories
//Горутины в Go на примерах. Как создать горутину в Golang

Горутины в Go на примерах. Как создать горутину в Golang

gorutiny v go na primerah kak sozdat gorutinu v golang 8e7cb0a - Горутины в Go на примерах. Как создать горутину в Golang

Веб-разработчик, фрилансер… Пишу об ИТ и смежных технологиях. Легковесная, потребляет мало памяти, имеет низкую задержку — знакомимся с горутиной.

gorutiny v go na primerah kak sozdat gorutinu v golang ffa283a - Горутины в Go на примерах. Как создать горутину в Golang

Язык Go, имеющий встроенную поддержку параллельного программирования, представляет вашему вниманию легковесные потоки, выполняющиеся в фоновом режиме. В отличие от потоков, существующих в большинстве других языков — они дешевле с точки зрения занимаемой памяти, межпотокового взаимодействия, имеют низкую задержку и быстрое время запуска. Хотите детальное описание этой сущности — читайте статью!

Определение потока в программировании

Любое работающее приложение, с технической точки зрения — это процесс или, скорее, последовательное выполнение набора инструкций. Эти инструкции исполняются по порядку: сначала первая, потом вторая, затем следующая и так далее. Этот процесс имеет начало и конец.

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

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

Однако, между ними все же есть различие.

Процесс — часть выполняемой программы, с выделенными специально для него системными ресурсами (процессорное время, память и т. д.). Поток же — это своего рода способ выполнения этого процесса.

Что такое Горутины?

Горутины — это дальнейшее усовершенствование концепции потока, а если сказать проще, то это функции, способные работать параллельно с другими такими же функциями в одном адресном пространстве. Причем их настолько хорошо усовершенствовали, что они стали отдельной сущностью. В многопроцессорной среде создание и обслуживание процесса сильно зависят от базовой операционной системы. Процессы потребляют ресурсы операционки и не делят их между узлами. Потоки, хотя и легче, чем процессы, из-за совместного использования ресурсов (между одноранговыми потоками), требуют большого размера стека — почти 1 МБ. Причем стек нужно умножать на количество потоков.

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

Преимущество горутин в том, что они не зависят от базовой операционной системы, а скорее, существуют в виртуальном пространстве среды выполнения Go. В результате любая оптимизация горутины меньше зависит от платформы, на которой она работает. Они начинают работать с начальной емкости стека размером всего 2-4 КБ и наряду с каналами поддерживают модели параллелизма взаимодействующих последовательных процессов (CSP), где значения передаются между независимыми действиями. Эти действия, как вы уже догадались, называются горутинами.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека Go разработчика» Интересно, перейти к каналу

Как создать горутину в Go

Разработчики должны понимать, что горутины превосходят потоки только количественно. Качественно они одинаковы. При запуске программы в Golang первая горутина вызывает основную функцию и из-за этого ее часто называют основной горутиной. Если же мы захотим создать другие, новые горутины, мы должны использовать оператор go. Например, чтобы вызвать функцию в Golang мы пишем так:

         myfunc()     

Здесь, после того как ее вызвали, мы опять вернемся к точке вызова. А теперь мы напишем:

         go myfunc()     

Префикс go вызывает функцию в новой горутине и она (функция) будет выполняться асинхронно с вызвавшим ее участком кода. И если примерно брать в среднем на одну горутину по 4 Кб емкости стека, то имея оперативную память 4Gb, мы сможем создать их около 800 000.

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

  1. Когда нам необходима асинхронность. Например, при работе с сетью, дисками, базами данных и т. д.
  2. При большом времени выполнения функции, когда мы можем что-то выиграть, нагрузив другие ядра.

Среда выполнения Go, работающая в фоновом режиме, начинает запуск набора горутин, с помощью планировщика, распределяющего их по машинам. Затем он создает поток, обрабатывающий все горутины, а максимум определяется переменной GOMAXPROCS.

Из документации Go: «Переменная GOMAXPROCS ограничивает количество потоков операционной системы, которые могут одновременно выполнять код Go на уровне пользователя. Количество потоков, которые можно заблокировать в системных вызовах от имени кода Go, не ограничено.

Давайте рассмотрим простой пример для лучшего понимания работы горутин:

         func main() { 	i:= 10 	go fmt.Printf("1. Значение переменной i равно %dn", i) 	i++ 	go fmt.Printf("2. Значение переменной i равно %dn", i) 	go func() { 	i++ 	go fmt.Printf("3. Значение переменной i равно %dn", i) 	}() 	i++ 	go fmt.Printf("4. Значение переменной i равно %dn", i) 	time.Sleep(1000000) }     

Запуск приведенного выше кода в вашем редакторе приведет к следующему результату:

         4. Значение переменной i равно 12 3. Значение переменной i равно 13 1. Значение переменной i равно 10 2. Значение переменной i равно 11      

Ниже приведен тот же код, только без использования горутин:

         func main() { 	i:= 10 	fmt.Printf("1. Значение переменной i равно %dn", i) 	i++ 	fmt.Printf("2. Значение переменной i равно %dn", i) 	func() { 	i++ 	fmt.Printf("3. Значение переменной i равно %dn", i) 	}() 	i++ 	fmt.Printf("4. Значение переменной i равно %dn", i) 	time.Sleep(1000000) }     

Здесь ожидаемый результат будет следующим:

         1. Значение переменной i равно 10 2. Значение переменной i равно 11 3. Значение переменной i равно 12 4. Значение переменной i равно 13      

Когда мы ставим перед любой функцией ключевое слово go, оно создает новую горутину и планирует ее выполнение. Идея и поведение такой сущности полностью идентичны потокам: она имеет полный доступ к аргументам, глобальным переменным и остальным доступным элементам кода. Кроме того, мы можем писать горутины с анонимными функциями. Если вы удалите вызов sleep() в первом примере, вывод не будет показан. Следовательно, вызов функции в конце main приведет к тому, что основная горутина остановится и выйдет до того, как порожденная ею горутина получит какой-либо шанс произвести вывод.

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

***

Если подытожить, то можно сказать, что горутины — это эффективное ресурсосберегающее средство достижения многозадачности в языке программирования Go. Более подробную информацию по их грамотному использованию можно получить на официальном сайте языка.

Материалы по теме

  • 🏎 К чему приводит обилие конкурентности в кодовой базе Go?
  • 🏃 Пишем мессенджер на Go за час: 7 простых шагов от эхо-сервера к асинхронному обмену сообщениями
  • 🏃 Самоучитель для начинающих: как освоить Go с нуля за 30 минут?

  • 1 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Свежие комментарии

    Рубрики

    About Author 01.

    blank
    Roman Spiridonov

    Моя специальность - Back-end Developer, Software Engineer Python. Мне 39 лет, я работаю в области информационных технологий более 5 лет. Опыт программирования на Python более 3 лет. На Django более 2 лет.

    Categories 05.

    © Speccy 2022 / All rights reserved

    Связаться со мной
    Close