Информация об изменениях

Сообщение Re[6]: Горутины и потоки от 28.06.2021 18:58

Изменено 29.06.2021 6:21 netch80

Re[6]: Горутины и потоки
Здравствуйте, gandjustas, Вы писали:

G>>>ОС не знает когда поток остановится и остановится ли вообще.

N>>Ну кроме случаев, когда нить сама делает вызов, который блокирует её выполнение )
N>>а таких действий в сетевой нагрузке и GUI, например, большинство.
G>А конкретнее?

Эээ... что именно конкретнее?

G>Если что планировщики ОС всгеда нормально справлялись с десктопной нагрузкой. необходимость обращатся с огромным количеством потоков есть только в сервреах.


А что из этого влияет на сказанное мной?
И IO bound, и CPU bound нагрузка может быть и на сервере, и на десктопе.

G>>> ОС прерывает выполнение по кванту времени, поэтому нужно сохвранить все текуще состояние (стек).

N>>При любом прерывании выполнения надо сохранить текущее состояние.
G>Только "контролируемое" прерывание потребует гораздо меньше места для сохраннеия, чем прерывание в произвольном месте.

Если это где-то действительно так, то там неэффективно используют ресурсы процессора — в первую очередь заполняют не все регистры.

(В частности, этим как раз отличается Go — там из-за NIH построения кодогенератора нет передачи аргументов и результатов функции в регистрах, всё на стеке, и даже внутри функций основная часть кода это прочитать из одного места стека и записать тут же в другое, а потом обратно.)

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

G>>> В "упавлемых" средах "поток" выполнения останавливается не тогда когда ОС решит, а тогда когда код дойдет до точки прерывания.

N>>И как определяется точка прерывания?
N>>В Go это точно так же как в случае ОС — переход в ожидание, или просто вызов чего-то в рантайме. Пустой вечный цикл в Go заблокирует целиком одну системную нить рантайма.
G>Это фактически означает что планирощик Го не может использоваться в ОС для всех потоков.

Про то, что недавно это таки исправили, уже написали.
Но в общем да, внутренний планировщик Go не может использоваться в ядре, или о чём речь?

N>>Оно ровно равно тут всему стеку плюс регистры (а не пространству, зарезервированному под стек).

G>В C# можно в явном виде увидеть состояние "продожения" в async\await, оно сильно меньше чем весь стек + регистры.

В таком случае сохранение и восстановление сделано внутренними средствами рантайма как раз на границе точки разрезания. Как это конкретно сделано — значения скинуты в стек, в состояние объекта или ещё куда-то — это уже второстепенно.
Re[6]: Горутины и потоки
Здравствуйте, gandjustas, Вы писали:

G>>>ОС не знает когда поток остановится и остановится ли вообще.

N>>Ну кроме случаев, когда нить сама делает вызов, который блокирует её выполнение )
N>>а таких действий в сетевой нагрузке и GUI, например, большинство.
G>А конкретнее?

Эээ... что именно конкретнее?

G>Если что планировщики ОС всгеда нормально справлялись с десктопной нагрузкой. необходимость обращатся с огромным количеством потоков есть только в сервреах.


А что из этого влияет на сказанное мной?
И IO bound, и CPU bound нагрузка может быть и на сервере, и на десктопе.

G>>> ОС прерывает выполнение по кванту времени, поэтому нужно сохвранить все текуще состояние (стек).

N>>При любом прерывании выполнения надо сохранить текущее состояние.
G>Только "контролируемое" прерывание потребует гораздо меньше места для сохраннеия, чем прерывание в произвольном месте.

Ну да, потому что необходимое для этого сохранение предварительно сделано (а потом будет восстановление) самим прерываемым кодом. Сохранения в идеальном варианте столько же, но отличается место и исполнитель. Если же кто-то видит суммарный объём действий по такому сохранению меньше, чем в варианте разрыва в произвольном месте, то там неэффективно используют ресурсы процессора — в первую очередь заполняют не все регистры.

(В частности, этим как раз отличается Go — там из-за NIH написания кодогенератора нет передачи аргументов и результатов функции в регистрах, всё на стеке, и даже внутри функций основная часть кода это прочитать из одного места стека и записать тут же в другое, а потом обратно.)

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

G>>> В "упавлемых" средах "поток" выполнения останавливается не тогда когда ОС решит, а тогда когда код дойдет до точки прерывания.

N>>И как определяется точка прерывания?
N>>В Go это точно так же как в случае ОС — переход в ожидание, или просто вызов чего-то в рантайме. Пустой вечный цикл в Go заблокирует целиком одну системную нить рантайма.
G>Это фактически означает что планирощик Го не может использоваться в ОС для всех потоков.

Про то, что недавно это таки исправили, уже написали.
Но в общем да, внутренний планировщик Go не может использоваться в ядре, или о чём речь?

N>>Оно ровно равно тут всему стеку плюс регистры (а не пространству, зарезервированному под стек).

G>В C# можно в явном виде увидеть состояние "продожения" в async\await, оно сильно меньше чем весь стек + регистры.

В таком случае сохранение и восстановление сделано внутренними средствами рантайма как раз на границе точки разрезания. Как это конкретно сделано — значения скинуты в стек, в состояние объекта или ещё куда-то — это уже немного менее важно.