Pull to refresh

Comments 16

Про то что не вытеснит горутину с for {x++;} — интересно.

А как Вы думали оно реализовано? В случайных местах в коде вставлены проверки? :)
В Go вообще не так уж и много происходит за кадром, ассемблер на выходе получается без сюрпризов, отсюда и вывод напрашивающийся, что переключение контекста происходит в особенные моменты в рантайме.

Да милионом способов реализовать можно.
Flaker, эх… такой вопрос классный был на собеседованиях) придётся теперь замену искать)

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

А точно ли в современных архитектурах присутствует проблема с False Sharing? Сейчас же есть разные уровни кэшей и технологии решающие эти проблемы. Например, протокол MESIF.

А каким образом MESIF эту проблему решает?

Go выбирает для себя подход CSP. Этот же подход используется, например, в таком языке, как Erlang.

У erlang модель акторов а не csp
Да, вы правы, сейчас это так. Хотел скорее написать, что на становление Erlang сильно оказала влияние теория Хоаровского CSP, и практическая реализация Smalltalk и Prolog.

Robert Virding (один из отцов Erlang) про это написал так: "Actually we had never heard of the actor model, not before ppl told us we had implemented it" (https://twitter.com/rvirding/status/766242280592277504)

Более подробное обсуждение можно вот тут почитать: elixirforum.com/t/does-earlier-erlang-concurrency-model-stem-from-csp/16905

Спасибо за ваше замечание, я поправлю текст!)

Основная проблема с решениями вроде errgroup и прочими заключается в том, что в Go все эти библиотеки — second class citizens.

С точки зрения языка нет же никакой разницы между стандартной библиотекой и внешними пакетами. Или речь не об этом?

go statement — часть языка, а не стандартной библиотеки. Будь это частью библиотеки, как в том же Kotlin, проблем было бы меньше. Но по факту, приходится городить всякие g.Go(func()), которые не равны go func()

Проблема не в инструменте, а отказе думать. Чтобы написать хорошо, нужно выбрать подходящий подход.


Если мы пишем на Go, надо использовать всю мощь языка. Пробуем. Получаем в три раза больше кода.

И показываете пример мощи WaitGroup. Вы незаметно отождествили "мощь Go" и "мощь WaitGroup".


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

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


Если оставить оркестрацию на ответственность вызывающего, код станет проще:


func call(ctx context.Context, requests <-chan Request, errors chan<- error) {
  for r := range requests {
    go func(r Request) {
      if e := send(ctx, r); e != nil {
        errors <- e
      }
    }(r)
  }
}

Я ошибся в том, что в моём коде вызывающий может оркестрировать выполнение запросов (не может, хотя это можно доработать), но главное утверждение всё ещё верно: в примере конкурентный код сложнее, потому что выполняет две задачи – отправку запросов и оркестрирование, – и если не делать оркестрирование, то последовательный и конкурентный код будут не особо отличаться как по объёму, так и по размеру.

В go1.14 горутины теперь асинхронно вытесняются и такие циклы без вызовов не заблокируют планировщик. Так что пример с бесконечным циклом уже не актуален
Sign up to leave a comment.