Предисловие
Я начинал с VB (Visual Basic), писал на C и Pascal, писал на языках для программируемых логических контроллеров (ST, SFC, FBD, LD), далее — PHP, немного Python, гораздо больше Kotlin, в качестве хобби изучал Rust и теперь решил посмотреть на Go. Изучая новый язык программирования, нужно придумать задачу, которая должна быть относительно простой, но при этом показательной, такой, чтобы язык проявился. Для Rust подойдёт любая задача — компилятор быстро начнёт бить вас по рукам, если вы не поняли основные концепции. Я переписал на Rust свою локальную утилиту mashinka, которая автоматизирует работу с блогом, в который я сейчас пишу этот пост. Потом я подумал проверить гипотезу и написать телеграм-бота. Приступая к Go, я уже читал код на этом языке и в целом имел некоторое представление о нём, о его фишках и преимуществах. Изначально я слышал, что у Go есть горутины, но понятия не имел, что это такое, кроме «лёгких потоков». Набор статей, которые я написал по корутинам Kotlin, очень помог, так как горутины — это корутины, хотя и реализованные в Go по-своему.
Я прошёл 'A Tour of Go' и решил попрактиковаться с горутинами. Эта часть языка для меня наиболее интересна. Читая тг-каналы, я наткнулся на excercism.io и задание по подсчёту символов в строке. Предлагалось сделать вариант с перебором и через горутины и сравнить результаты. Это задание я и решил использовать для прокачки и закрепления знаний.
Из простого задания получился небольшой проект, который можно запустить и убедиться в том, что горутины дают эффект ускорения. Любой может взять этот проект и попробовать на своём компьютере.
Описание
CLI-приложение, которое выполняет подсчет частоты символов в строках. На входе задаем режим(mode): c, s, b. Где c — это конкурентный режим (горутины), s — обычный (без горутин) и b — оба(с + s). Через запятую после режима можно задать желаемый размер массива и желаемый размер строки. Строки генерятся автоматически и случайным образом из набора символов (см. функцию GenerateRandomString).
Для запуска программы нужно выполнить команду (Linux): go run count_freq_letters.go
и далее ввести параметры или нажать enter для запуска с параметрами по умолчанию. По умолчанию программа стартует с параметрами b 10000 10000 и выводит результаты. Режим S — это обычный обход в цикле с подсчётом числа символов в строках. Режим C делает то же самое, что и S, но каждую строку обрабатывает в отдельной горутине (конкурентно).
После завршения выведет результаты: время выполнения после Took и данные, где ключ — это символ, а значение — это частота появления в тексте.
Выводы
Даже программа, созданая для решения конкретной задачи требует чуть больше, чем рабочий алгоритм. Разные режимы разбиты на модули, которые импортируются в основную программу. Для входных данных используется структура InputData, которая хранит входные параметры. Для корректной работы режима "C" выполняется синхронизация с помощью mutex, а ожидание завершения горутин реализовано через WaitGroup.
Конкурентный режим проявляет себя на больших объёмах, а на малых проигрывает последовательному перебору. Причина тому — работа mutex: если строки короткие и их много, то системе приходится часто переключать mutex, а это требует времени. Чем длиннее строка, тем меньше блокировок. Это не сразу показалось мне очевидным, и я вначале думал, что с моей реализацией что-то не так.
В текущей реализации нет ограничения на число горутин. Это дополнительная работа. Нужно писать так называемый WorkerPool.
В текущей реализации нет контроля состояния горутин: если в одной из горутин возникнет проблема или она зависнет, это приведёт к утечке. Я также не решал это в рамках этой программы, но это актуально для, например, веб-сервиса.
Прошлые записи
- DYI. Гипсовый карниз своими руками
- Комната призвания
- Разбираемся с Coroutine в Kotlin - часть четвертая
- Разбираемся с Coroutine в Kotlin - часть третья
- Разбираемся с Coroutine в Kotlin - часть вторая
- Разбираемся с Coroutine в Kotlin - часть первая
- Отпуск длинною в год
- Подходит ли data class для JPA Entity?
- События как источник правды или как я в стартапе участвовал
- Код 2015 против 2023