обучение

Разбираем конкурентность в Go: книги, блоги, выступления

258
0
24 марта 2025
Изображение создано с помощью нейросети
обучение
258
0
24 марта 2025
Разбираем конкурентность в Go: книги, блоги, выступления

Особенность Go — удобный механизм конкурентности. Создавать конкурентные задачи в парадигме языка можно буквально «бесплатно» и предельно просто: достаточно написать ключевое слово go перед вызовом функции — и она начнет выполняться независимо от породившего ее потока.

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

Я Владислав Белогрудов, эксперт по разработке ПО в YADRO. В свое время изучал различные источники и лучшие практики в поиске эффективных способов организации параллельных процессов в Go. Делюсь ими с вами.

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

Выступление Роба Пайка про конкурентность в Go

Горутина — это легкий поток выполнения, который создается с помощью слова go перед вызовом функции. Она запускается асинхронно и не требует отдельного потока ОС — runtime Go самостоятельно решит, как распределять горутины по имеющимся в наличии потокам операционки. Горутины работают в одном адресном пространстве и управляются планировщиком Go, что делает их гораздо легче, чем системные потоки.

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

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

Блог Дейва Чени

Полезные материалы про конкурентность в Go можно найти в блоге Дейва Чени. Дейв, в целом, рассматривает разные решения в Go: как они появились и как ими пользоваться. И тему конкурентности он не обошел стороной. Например, в статье Curious Channels Дэйв Чейни рассказывает о двух важных свойствах каналов в Go:

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

В отличие от языков вроде C, где для управления потоками используются блокировки и разделяемая память, в Go конкурентность реализована через более простые и безопасные инструменты. Однако, несмотря на удобство, работа с каналами требует понимания нюансов, о которых Дэйв Чейни подробно рассказывает в своих статьях.

Подробнее про сравнение подходов к реализации пула потоков на языках программирования C и Go в статье.

Продвинутые паттерны от Google

Доклад Advanced Go Concurrency Patterns представил Самир Аджмани из Google на конференции Google I/O 2013. Автор рассказал, как эффективно управлять конкурентными процессами с помощью горутин и каналов. Главные темы его выступления:

Горутины и каналы в Go

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

Шаблоны проектирования для конкурентных программ

Обсуждаются несколько шаблонов, включая:

  • Fan-in и Fan-out — управление данными из нескольких источников или их распределение.
  • Worker Pool — распределение задач между горутинами.
  • Fan-in и Fan-out — управление данными из нескольких источников или их распределение.
  • Pipeline — последовательная обработка данных через цепочку горутин.

Обработка периодических событий и отмена операций

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

Использование select для управления конкурентностью

Оператор select позволяет управлять несколькими каналами одновременно и обрабатывать события, не блокируя выполнение.

Предотвращение deadlock и обработка ошибок

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

Актуальная статья из 2014 года

Статья Go Concurrency Patterns: Pipelines and cancellation разбирает паттерны работы с потоками в Go: объединение и разбиение потоков, worker pool, fan-in, fan-out и другие. Хотя ее написали в 2014 году, в ней много полезных идей с примерами, которые могут пригодиться изучающим конкурентность в Go.

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

В статье приводится простой пример конвейера, состоящего из трех этапов:

  1. Генерация чисел (gen): функция принимает список чисел и преобразует его в канал, по которому эти числа отправляются.
  2. Возведение в квадрат (sq): функция принимает числа из входящего канала, возводит их в квадрат и отправляет результаты в исходящий канал.
  3. Потребление результатов: функция main настраивает конвейер и выводит результаты, полученные из предыдущего этапа.

Книжная классика в Go

Concurrency in Go: Tools and Techniques for Developers, Кэтрин Кокс-Будей

Книга предлагает глубокое погружение в тему параллельного программирования на языке Go. Автор понятно объясняет принципы работы с конкурентным кодом, а также дает рекомендации по его организации, чтобы избежать распространенных ошибок. В отличие от многих видео, где объяснения могут быть непонятными, в книге информация представлена в легком для усвоения и применения на практике формате.

Разворот книги Кэтрин Кокс-Будей
Разворот книги «Concurrency in Go: Tools and Techniques for Developers»

Основные темы:

  • Основы горутин и каналов.
  • Паттерны проектирования для эффективной конкурентности.
  • Управление состояниями и обработка ошибок.
  • Практические советы и примеры реальных приложений.

Functional Programming in Go, Дилан Миус

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

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

Разворот книги Дилана Миус
Разворот книги «Functional Programming in Go»

В ней можно найти:

  • Основы функционального программирования и их применение в Go.
  • Использование функций высшего порядка и замыканий для гибкости и модульности.
  • Реализацию неизменяемых структур данных и их преимущества.
  • Функциональные паттерны для обработки ошибок и конкурентности.

Вместо заключения

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

Перед написанием конкурентного кода важно задать себе два вопроса:

  1. Нужен ли он вообще? Возможно, это лишняя сложность.
  2. Нужна ли многопоточность или можно обойтись стандартными библиотеками?

Например, есть известная библиотека от разработчика Сэмблера, которая умеет параллельно обрабатывать данные — фильтровать длинные списки, выполнять MapReduce и другие задачи. Благодаря ей не приходится изобретать «велосипеды» и писать лишний код.

А какие полезные материалы про конкурентность в Go можете назвать вы? Делитесь в комментариях.
Наверх
Будь первым, кто оставит комментарий