Как стать автором
Обновить

Комментарии 29

Проверка прекращения работы worker’ов

По-моему здесь присутствует race condition. Нет гарантии, что первой прочитает из канала горутина, а не основной поток. Да и есть https://golang.org/pkg/sync/#WaitGroup
Согласен, ответ от горутины лучше слать в другой канал.
И сам лично тоже использую WaitGroup.
Пример из оригинальной статьи, править не стал.
Операция отправки в канал заблокируется, пока горутина не начнет чтение из него. Так что там все ок. Для одной горутины частенько использую такой вариант. В других случаях действительно удобно отдельным каналом слать факт завершения. А для нескольких уже конечно WaitGroup.
Да, вы правы, забыл, что по-умолчанию ёмкость канала 0, а не 1.
Если в руках есть только молоток (каналы), то все проблемы кажутся гвоздями. Ничего хорошего в этом нет, это не называется "фантастической поддержкой конкурентности". Больше (кроме locks еще) ничего нет не потому что не надо, а потому что дизайнеры дают очень высокий приоритет маленькому кол-ву концепций (и, видимо, простоте рантайма). То есть решают свою проблему, чтобы быстрее добавлять новые фичи и улучшать другие моменты, а не проблему пользователей. Они делают это в интересах пользователей, конечно, но в ином разрезе. Поэтому не всякий аспект языка Го является "великолепным" и "фантастическим" (а другие).
Рантайм там как раз очень непростой. Простые конструкции языка, а за ними сложный и мощный рантайм, чтобы это действительно было "великолепным" и "фантастическим"
Может быть, но добавить локи, семафоры и т. д. можно только путем впиливания прямо в рантайм, что сделает его еще сложнее.

С одной стороны, Го хвалят за простоту, с другой, подход с впиливанием фич прямо в рантайм (мапы, слайсы, каналы, и т. д.) вместо предоставления примитивов, на которых это все можно построить библиотечным кодом — может очень сильно аукнуться через 5-10 лет.

В этой связи интересно сравнение с Rust, который последние года 2 перед релизом целенаправленно "сушил" рантайм и достиг в этом успехов
В райтайм впилены самые необходимые вещи по мнению авторов. Зачем? Потому что только так их можно сделать максимально удобными и лаконичными. Каналы и горутины так хороши именно потому, что они часть спецификации языка и его синтаксиса. Если исключить их оттуда, то мы получаем опять С++, где много всего, но им невозможно и неудобно пользоваться. Не дай бог в новый стандарт асинхронные функции включат не как синтаксис, а как функции STL. Этим опять будет невозможно пользоваться. C#, опять же, показывает, что async/await так прекрасно работают, потому что включены в сам язык, компилятор, рантайм.

Что до простоты. То это частое заблуждение, я смотрю, которое я для себя развеял, когда услышал из первых уст. Команда Go никогда не стремилась к простоте везде. Им нужен был простой язык с простой спецификацией и концепциями, но никто не говорил, что внутри там все просто. Напротив, они специально за простыми конструкциями прятали очень сложные вещи вроде каналов и горутин со своим планировщиком задач и кооперативной многозадачностью с маленькими проблесками вытесняющей. Тот же сборщик мусора — он вообще разработчику не виден, команда даже намеренно не дает никаких средств его настройки, но внутри он совсем не прост, особенно в последних релизах.
Если исключить их оттуда, то мы получаем опять С++, где много всего, но им невозможно и неудобно пользоваться. Не дай бог в новый стандарт асинхронные функции включат не как синтаксис, а как функции STL. Этим опять будет невозможно пользоваться. C#, опять же, показывает, что async/await так прекрасно работают, потому что включены в сам язык, компилятор, рантайм.

Посмотрим на примере Раста, можно этим будет пользоваться, или нет.

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

На мой взгляд, ничего особо сложного, по сравнению со сложностью рантайма Java, или, например, сложностью компилятора C++, в Го нет. Потому-то они и выкатили очень и очень достойную реализацию всего за пару лет, при том, что над ней работало поначалу меньше 10 человек, а сейчас — не сильно больше.
На мой взгляд, ничего особо сложного, по сравнению со сложностью рантайма Java, или, например, сложностью компилятора C++, в Го нет

Сначала вы жалуетесь на сложность рантайма, теперь оказывается ничего особо сложного там нет. Сложный там рантайм и таковым стал к нынешним версиям. Зеленые потоки, стек динамического размера, конкурентный сборщик мусора — это совсем не простые вещи. Что до java, то ее можно назвать сложной разве что при условии JIT компиляции. Уж интерпретируемая виртуальная машина вообще задача для студента. А сборщик мусора и там и там есть довольно непростой.

Потому-то они и выкатили очень и очень достойную реализацию всего за пару лет, при том, что над ней работало поначалу меньше 10 человек, а сейчас — не сильно больше.

Как раз достойной реализация тогда не была. Сборщик мусора был тормозной и убогий — stop the world вариант. Планировщик был так же тупой и медленный. С тех времен рантайм сильно изменился. Ну и как бы опыт у людей уже был. Это не первый язык авторов с подобными фичами.
Сначала вы жалуетесь на сложность рантайма, теперь оказывается ничего особо сложного там нет. Сложный там рантайм и таковым стал к нынешним версиям. Зеленые потоки, стек динамического размера, конкурентный сборщик мусора — это совсем не простые вещи. Что до java, то ее можно назвать сложной разве что при условии JIT компиляции. Уж интерпретируемая виртуальная машина вообще задача для студента. А сборщик мусора и там и там есть довольно непростой.

Я нигде не жаловался на сложность рантайма. Я предположил, что авторы ограничились молотком-каналами (и "так и быть", подумали они, простейшими локами), чтобы рантайм был прост, и они могли в 10-20 человек за несколько лет довести его до приличного уровня. Java пилят сотни людей десятки лет. Мы о Hotspot JVM конечно, а не студенческих задачах.

Современные Java-сборщики сложнее, потому что они перемещают объекты, и тоже конкурентные.
Мне все так же непонятно, о чем вы вообще пишите. То сложный рантайм, то не сложный, яву зачем-то приплели и никаким образом не влияющий ни на что факт, что ее пилят черти сколько лет (при том, что в яве за это время прогресса, по сути, никакого и нет).

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

Go сборщик мусора не перемещает вроде бы объекты в куче, но и не дает гарантий, что не будет этого делать в будущем. А вот стек может запросто переместиться при смене его размера, а с ним и объекты в нем.
Я не совсем понял мысль про "впиливание" локов и семафоров в рантайм, можете пояснить? И каким образом это влияет на сложность?
Кооперативная многозадачность горутин описана не доступными для авторов библиотек (т. е. пользователей языка) примитивами, а только в спеке, и реализована внутри рантайма. Поэтому рантайм должен знать про все, что может "переключать" горутины (каналы и локи в данном случае), и нельзя добавить сбоку какой-нибудь семафор, без описания его логики прямо в рантайме.
Да, без примера не разобраться. А что мешает использовать семафоры?
Ну то-есть я вижу это так, каждый примитив выполняет свою роль. Семафоры блокируют выполнение горутины при доступе к общему ресурсу, по сути и выполняют свое предназначение. Какое еще влияние они должны оказывать на них?
Кооперативная многозадачность горутин описана не доступными для авторов библиотек (т. е. пользователей языка) примитивами, а только в спеке, и реализована внутри рантайма.

В этом и есть высшее благо. Зеленые потоки зашиты в сам язык. Поэтому им так легко и удобно пользоваться. Любое иное решение будет хуже в любом случае. Может еще давайте из erlang уберем из рантайма зеленые потоки, потому что они слишком много прячут? Это не С++.

У вас есть все простейшие примитивы, чтобы реализовать более сложные конструкции. Кооперативная многозадачность в последних версиях достигается так же засчет вставки вызовов планировщика перед каждым вызовом функции, а кроме каналов и локов там еще участвуют IO операции. Планировщик можно и самому вручную вызвать. Мне все так же непонятно, что вам не нравится. Вам стоит изучить язык по-лучше, раз так интересно.
У вас есть все простейшие примитивы, чтобы реализовать более сложные конструкции.

Этим "простейшим примитивом" являются каналы, что как раз иллюстрирует эта статья — все реализуется через каналы. Это работает, но 1) не очень эффективно 2) не очень интуитивно

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

Мне все так же непонятно, что вам не нравится.
Мне не нравится чрезмерные восторги по поводу того, что через каналы можно сконструировать разные синхронизированные конструкции. В том же C++ все это можно реализовать более эффективно, и выглядеть будет хуже разве что из-за громоздкости синтаксиса, а по сути будет проще.
что как раз иллюстрирует эта статья — все реализуется через каналы

Эта статья называется "способы использования Go каналов". Вы ожидали увидеть в ней способы реализации не через каналы?
Этим «простейшим примитивом» являются каналы, что как раз иллюстрирует эта статья — все реализуется через каналы. Это работает, но 1) не очень эффективно 2) не очень интуитивно

Достаточно эффективно, чтобы использовать это повсеместно. Предельно интуитивно и просто. Вы явно не пользовались каналами. В сравнении с привычными локами по всему коду и колбеками это несравнимо проще и понятнее, а за счет поддержки со стороны языка проще и понятнее даже попыток реализовать все это библиотекой в другом языке. Это при том, что локами никто не мешает пользоваться и активно пользуются там, где это проще, чем каналы.

Да, я в курсе, про все это рантайм тоже знает. Идея в том, что переключить выполнение с одной горутины на другую, либо сделать «пинг» какой-нибудь спящей горутины, никак нельзя, кроме как через все те же пресловутые каналы.

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

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

Мне не нравится чрезмерные восторги по поводу того, что через каналы можно сконструировать разные синхронизированные конструкции. В том же C++ все это можно реализовать более эффективно, и выглядеть будет хуже разве что из-за громоздкости синтаксиса, а по сути будет проще.

Вам не нравится, а оно работает и очень успешно. С помощью С++ можно много чего сделать, но вопрос в том, чтобы променять довольно условную эффективность на намного более понятный и лаконичный код, который может не только доктор наук писать, а даже джуниор. С++ никто не трогает там, где его не заменить — высокопроизводительный код. У того же Google ключевые элементы инфраструктуры с него никуда не переедут, но их единицы. В основном все можно переписать на Go и получить несравнимо более простой и масштабируемый код, а проиграть довольно несущественно в эффективности.
Тем не менее, концепция каналов является весьма мощной (о чем, собственно и пост). Для низкоуровневых вещей доступны локи и атомарные операции, а концептуальная лаконичность языка это скорее плюс, чем минус.
Может быть каналы даже тьюринг-полны. В машине Тьюринга очень мало концепций, но это не плюс для программирования на ней. Тут нужен баланс, который Го, мне кажется, чуть-чуть проскочил.
Меня очень заинтересовал пример с HeartBeat. А есть ли возможность запускать не одну, а большое число рутин одновременно по такому вот таймеру? Или я чего-то не правильно понял...
Да сколько угодно, просто в каждой создаете свой heartbeat канал. Учитывайте, что если горутины будут завершаться (т.е. не будут работать все время жизни процесса), то этот канал не будет подчищен сборщиком мусора, будет утечка.
Это просто выполнение какого-то кода через равные промежутки времени. Можно сколько угодно таких рутин создать, у каждой будет свой такой таймер, и они будут конкурентно выполняться. Мне несколько непонятен даже вопрос.
Имеется ввиду, чтобы у всех рутин был один и тот же таймер. Ну, даже может быть не таймер, а к примеру такой "генератор синхронизации", который при тике запускает сразу все подписанные на него рутины
Для синхронных тиков? Тогда придется писать размножитель сигнала, т.к. исходный тик из канала сможет забрать только одна горутина, даже если этот канал будут слушать много горутин. Размножителю придется рассылать сигнал в индивидуальный канал каждой горутине.
https://blog.golang.org/pipelines
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории