170 похожих чатов

Привет, чатик! А как гошка раскидывает работу по тредам ОС? Я думал,

что рантайм горутину отдаёт в тред и она там крутится. А оказывается, что одна часть горутины выполняется в одном треде ОС, а другая часть горутины в другом треде ОС.


Взять простой пример:

$ cat test.go
package main

import (
"net/http"
"fmt"
"time"
"strconv"
)

func main() {
time.Sleep(2 * time.Second)
fmt.Println("let's go!")
for i:=0; i<20; i++{
fname := "func"+strconv.Itoa(i)
go doJob(fname)
}
time.Sleep(7 * time.Second)
}

func doJob(fname string) {
fmt.Println(fname)
resp, err := http.Get("http://ya.ru/")
fmt.Println(resp, err)
time.Sleep(5 * time.Second)
}

Стрейсим (до сих пор не пойму где ставить 2>&1, лол):

2>&1 strace -f go run test.go > /tmp/strace.goha 2>&1



А потом анализируем.


Сискол write() вызывался только в двух ОС тредах: 16502 и 16504:
$ grep write /tmp/strace.goha | grep func | cut -d' ' -f 2 | sort | uniq -c | sort -nrk1
19 16502]
1 16504]

При этом в потоке 16502 сокет открывался только 9 раз, что не совпадает с числом вызовов write() - 19:
$ grep 'socket(' /tmp/strace.goha | cut -d' ' -f 2 | sort | uniq -c | sort -nrk1
25 16506]
22 16509]
14 16505]
11 16508]
10 16510]
9 16504]
9 16502]

Какая тут логика?

17 ответов

27 просмотров

c go 1.14 планировщик у нас preemtible. Те неважно в какой стадии находится горутина - ее можно прервать и вызывать другую на том же треде Очень занимательный видос как это работает и как не получилось сделать https://www.youtube.com/watch?v=1I1WmeSjRSw

Elmanov Anton
c go 1.14 планировщик у нас preemtible. Те неважно...

причина зачем это сделано - сборщик мусора. он вынужден останавливать все треды периодически.

Andrey-Enshin Автор вопроса
Elmanov Anton
c go 1.14 планировщик у нас preemtible. Те неважно...

> Те неважно в какой стадии находится горутина - ее можно прервать и вызывать другую на том же треде Ну это вроде норм. А вот зачем горутину переносить в другой тред ОС? Я думаю, что рантайм дробить горутину на части и какие-то части отдаёт одному треду, а какие-то другому. Например, сетевые сисколы в один тредик, файловые - в другой. Об это как-то говорил @onokonem , но деталей не было. Спасибо за видос. Посмотрю

Andrey-Enshin Автор вопроса
Elmanov Anton
причина зачем это сделано - сборщик мусора. он вын...

кстати, он обязательно стопит все треды разом, типа стоп мир по всем фронтам или таки может почистить сначала один тредик ОС, потом другой?

Elmanov Anton
c go 1.14 планировщик у нас preemtible. Те неважно...

Это не совсем так. Вытеснение используется только как fallback

Andrey Enshin
> Те неважно в какой стадии находится горутина - е...

> А вот зачем горутину переносить в другой тред ОС? потому что треды это воркер пул, который выполняет горутины. и порядок там сложно предсказать. как раз таки ассоциировать рутину с тредом было сложнее, имхо

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

стопит все разом но на 2 коротких этапа - доли микросекунд. между ними работает конкурретно и без блокировок.

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

Daniel Podolsky
Это не совсем так. Вытеснение используется только ...

в видосе что выше скинул, про вытеснение говорят как про основной метод остановки рутин для переключения. видос 20го года про го 1.14 - должно быть актуально. можете кинуть ссылок в уточняющий источник плз

Daniel Podolsky
если горутине надо поспать, например, в ожидании с...

именно отправляет или помечает, что горутину можно выполнить?

c
а в чем разница?

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

Elmanov Anton
в видосе что выше скинул, про вытеснение говорят к...

я видос смотреть сейчас не буду, поэтому и спорить с ним не стану.

Daniel Podolsky
я видос смотреть сейчас не буду, поэтому и спорить...

там микс подходов с GC, но якобы OS signals основной и единственный способ остановки.

Alexey Ermakov
ну, сразу к треду привязать или возможно сразу вып...

там есть глобальная и локальная очередь, и, если мне не изменяет память, шедулер после I/O помещает в локальную

c
там есть глобальная и локальная очередь, и, если м...

локальная это локальная для P (m-p-g) имеется в виду?

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
13
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
Ребят в СИ можно реализовать ООП?
Николай
33
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
6
в JclConsole объявлено так: function CtrlHandler(CtrlType: DWORD): BOOL; stdcall; - где ваше объявление с stdcall? у вас на картинке нет stdcall
Karagy
8
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
program test; {$mode delphi} procedure proc(v: int32); overload; begin end; procedure proc(v: int64); overload; begin end; var x: uint64; begin proc(x); end. Уж не знаю...
notme
6
Карта сайта