All streams
Search
Write a publication
Pull to refresh
4
0
Alex Bubnov @nwalker

Пользователь

Send message
Не буду спорить, с D я не могу так навскидку разобраться, как там рантайм устроен.
Ничего удивительного там нет, однако уже есть годный multicore планировщик с work stealing и уже написан неплохой враппер для асинхронного i/o на горутинах.

Повторюсь, для Go оно уже есть, для D — непонятно когда будет и будет ли. Вся разница в этом.
Так в Go тоже же самое, просто эти yield-ы спрятаны внутрь операторов работы с каналами и код работы с сетевым i/o. Я же говорю, файберы из D _по сути_ идентичны горутинам.

Там могут быть различия в реализации, но суть та же.
> В go только один тип, поэтому такой проблемы нет и не нужно городить «синтаксический мусор».
Судя по короткому экскурсу в std.concurrency D — тамошние файберы работают как горутины и Fiber.yield возвращает с любого уровня вложенности вызовов => синтаксический мусор не нужен.
> D на голову лучше Go
Не, ну давайте все же будем честны — в плане concurrent рантайма и интеграции его с event loop D до Go еще расти и расти, а кто будет за это платить — неясно.
А, ну ок, я не тот мессидж прочитал.

BTW, в корректности вот этого тезиса

> если горутина слишком долго тупит
> (это может быть и не системный вызов), то
> создается еще тред, в который запихиваются другие горутины

я ощутимо сомневаюсь, но не настолько ориентируюсь в планировщике Go, чтобы уверенно отрицать.
В Go 1.5 GOMAXPROCS по дефолту ставится равным числу ядер, соответственно, горутины выполняются на нескольких тредах по умолчанию.
То есть, ваш пример не демонстрирует ничего, кроме стандартного поведения.
Ага, конечно. От кривых рук спасают иммутабельность(Haskell, Clojure), share nothing(Erlang) или move semantics(Rust, C++11+).
В Go есть только соглашения и рекомендации, никакой реальной защиты они не предоставляют.
Затем, что это единственный способ абстрагироваться от типа обрабатываемых данных. interface{} в Go, это как void* в С.
В языках с более развитой системой типов для этого существуют дженерики, но в Go они нинужны, это все знают.
> единственный язык, где об этом не нужно думать, это Rust.
Ну почему же. Есть Erlang, Haskell, Clojure, где об этом точно не надо думать.

А рантайм Erlang-а, например, достаточно умен, чтобы выполнять блокирующие системные вызовы на отдельном пуле тредов, что делает работу системы еще более предсказуемой.
Еще можно сравнить скорость переключения, но ежу понятно, выиграют зеленые треды, где нет трипов в ядро на переключение контекста, они для этого и придуманы.
Вот, я же говорил, дженерики нинужны.

BTW, https://gist.github.com/kachayev/21e7fe149bc5ae0bd878 — «Channels Are Not Enough or Why Pipelining Is Not That Easy», отличное чтиво, как раз по теме.
Они нинужны же.
В C# от него защищают async/await, если я все правильно понимаю.
> «юзер-спейс треды» не мешают использовать thread local storage.

В общем случае именно мешают, поскольку никто не гарантирует, что они выполняются на одном OS-треде(да и вообще, на кой они такие нужны, если на одном треде), и что они выполняются на одном и том же треде.
Вот, кстати, отличный пост по теме http://morsmachine.dk/go-scheduler
Вы опять путаете. Горутины выполняются на тредах ОС как N:M. В go 1.5 стартовое количество тредов, GOMAXPROCS равно количеству логических ядер в системе. В вашем примере на моем рабочем компе 8 тредов, по количеству ядер. В go 1.3.3 тредов 4, чем это обусловлено мне сейчас все же некогда разбираться.

Блокировка горутины не обязательно вызывает блокировку треда: network I/O, time.Sleep(), ожидание на канале и ожидание на примитивах из sync не вызывают блокировки треда, а только снимают горутину с выполнения до какого-то события.

Блокировка треда совпадает с блокировкой горутины при выполнении системного вызова(syscall). Например, все file I/O, включая, вроде бы, консоль. Так же тред условно блокируется уже упомянутой runtime.LockOSThread(), на нем выполняется только горутина вызвавшая LockOSThread() и никакие другие до завершения этой горутины.
Я сейчас уже не вдамся в подробности, когда именно создается новый тред вместо заблокированного, но в какой-то момент создается точно.

Кстати, все вызовы через cgo считаются syscall-ами и в неблагоприятных условиях могут жрать треды только так. Если глянуть в https://github.com/golang/go/blob/master/src/runtime/cgocall.go#L86, желание использовать cgo из более чем одной-двух горутин полностью исчезнет.

Go Scheduler Design Doc — https://golang.org/s/go11sched
Исходники рантайма тоже рекомендуются к чтению.

Кстати, плевок в сторону подхода авторов Go — почти ничего из написанного выше не описано в официальной документации, в т.ч. и откровенно неприятные особенности cgo.
BTW, в Linux уже 10 лет как нормальные треды.
> При этом другие горутины спокойно могут выполняться в параллельных процессах.
Ну где ж вы процессы там увидели.

Ну и да, эту функцию можно использовать исключительно понимая, что делаешь.
> runtime.LockOSThread()
> к текущему _процессу_ ОС

Я надеюсь, это опечатка?

Information

Rating
Does not participate
Location
Новосибирск, Новосибирская обл., Россия
Date of birth
Registered
Activity