vak: (Default)
[personal profile] vak
В языке Rust есть интересная фича: кооперативная многозадачность, реализованная в форме async/await и future. Интересно, можно ли на её основе сбацать простой симулятор цифровой логики. Когда-то я сделал такое на простом Си ("Симулятор RTL - это очень просто"). Но в Си пришлось задействовать setjmp/longjmp для переключение потоков, а тут вроде всё нужное прямо в языке дано.

Имеется хорошая статья, объясняющая подробности кооперативной многозадачности в Русте: https://os.phil-opp.com/async-await/

Date: 2021-04-16 01:25 (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi
По идее да. Ресурсы-то все поделены. Берем взаймы - отдаем.

Date: 2021-04-16 05:40 (UTC)
mopexod: (Default)
From: [personal profile] mopexod
Сколько я не пользуюсь async/await, так и не смог проникнуться принципиальным замыслом.

Ведь когда мы ждём I/O, у нас OS сама отбирает timeslices by preemptive multitasking, причём именно в тот самый момент, когда мы делаем await в high-level language. А если не ждём I/O, то и отдавать нам добровольно нечего (а OS отбирает всё равно :).

Остаётся, конечно, экономия на деталях имплементации - в сервере нужно меньше managed threads, в GUI мы не блокируем UI, но как общая идея это как-то мелковато.

Кооперативная многозадачность была в 16-битных Windows, и как-то сразу было понятно, что так жить нельзя.

Date: 2021-04-16 05:58 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
Принципиальная выгода в экономии количества стеков.
Это заметно, если по умолчанию выделять под стек каждому Thread по 4 MB.

В то же время в Windows можно экономно делать стек 128 KB. И так вместить много тысяч тредов.



Date: 2021-04-16 06:42 (UTC)
mopexod: (Default)
From: [personal profile] mopexod
Да, про экономию тредов/стеков я понимаю. Но как принципиальная идея - это как-то мелковато.

Date: 2021-04-16 07:30 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
Есть еще плюс: решение проблемы с Race Condition
С кооперативной многозадачностью можно писать без конкурентного доступа к данным.

Date: 2021-04-16 08:12 (UTC)
mopexod: (Default)
From: [personal profile] mopexod
Пожалуй, нет. У нас нет гарантии, что всё выполняется на одном треде.

Date: 2021-04-16 10:02 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
Я имел в виду, что с кооперативной можно обойтись без примитивов вида Mutex. Взамен высокоуровневые примитивы для обмена сообщениями (например Task Parallel Library в .NET).

А например в JavaScript всё в одном Thread, а албтернатива async/await - только цепочки континуаций.

Date: 2021-04-16 16:52 (UTC)
mopexod: (Default)
From: [personal profile] mopexod
Про JavaScript я почти совсем не в курсе.
А для С# и, видимо, Rust, кооперативные await/async никак не влияют на возможные способы синхронизации, так как не отменяют существующей preemptive, которая никуда не девается (ну, imho).

Тут, конечно, хорошо бы пример проекта, который перевели на await/async, и "всё прямо стало лучше", или "ничего не изменилось", но у меня такого нет. У меня все проекты с самого начала - или "threads по старинке", или "await/async".

Date: 2021-04-16 18:45 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
Типовые Web-приложения при переводе со старого ASP.NET на ASP.NET Core заодно переводят на async/await, потому что MS рекомендует.
Думаю, это один из немногих оправданных случаев, потому что параллельных запросов может быть очень много.
На десктоп приложениях я бы не связывался с async, польза не перевешивает сложности.

Есть известная статья про асинхронщину в виде метафоры красных и синих функций
https://habr.com/ru/post/466337/

Date: 2021-04-16 19:16 (UTC)
mopexod: (Default)
From: [personal profile] mopexod
Да, я, собственно, под ASP.NET в разных проектах делал и async/await, и просто обработку в thread pool.
Это была не главная поисковая страница Гугла, так что у меня не было тысячи запросов в секунду, но десятки были легко.
Честно говоря, никакой разницы в performance я не заметил. Вот и любопытно, обнаружил ли эту разницу кто-нибудь...

Date: 2021-04-16 21:01 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
Для честного тестирования надо иметь Одно и то же приложение в 2-х вариантах: sync & async.
Маловероятно что кто-то поддерживает так 2 ветки.

Я полагаю, производительность не сильно отличается в нормальном режиме,
Но когда появляются запросы которые подвисли, например по причине ожидания внешних сервисов, то в варианте с Thread Pool начнется голодание

Date: 2021-04-17 07:18 (UTC)
mopexod: (Default)
From: [personal profile] mopexod
Да, согласен.

Date: 2021-04-16 06:38 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
Вот отлаживать это намного труднее.
Исчезает привычный Stack Trace, вместо этого видно произвольный набор методов, которые завершились и как continuation вызвали другой Future и так по цепочке...

Date: 2021-04-17 07:07 (UTC)
sab123: (Default)
From: [personal profile] sab123
На самом деле стек трейсы все равно существуют, но в другой форме. Стековые фреймы сопрограмм располагаются в динамической памяти, и они связаны с фьючерами. Когда на этот фьючер выполняется await - это аналог адреса возврата в обычной программе. То есть, чтобы получить аналог стека, надо проследить цепочку авэйтов.

Тут есть два дополнительных момента:

1. Хоть C++ные, хоть Растовые сопрограммы опираюся на подсовываемую им библиотеку фьючеров, поэтому проблема отслеживания таких псевдостеков падает на эти библиотеки. Плюс отладчик. Но они все этого не умеют отслеживать.

2. Есть ситуации, когда отображение идет не напрямую 1:1, а N:1. Если реализоввать это в лоб, то оно делается циклом, и тогда первый фьючер попадает в цепочку, а остальные - нет, и неочевидно, к какому месту они прицепляются. Аналогично существуют и другие ситуации, когда фьючер не сразу соединяется с ожидающим его кодом, а заныкивается до лучших времен (другой типовой пример - пуб буферов фиксированного размера и ожидание пустого буфера когда они все заняты).

Date: 2021-04-17 15:49 (UTC)
From: [personal profile] sergegers
VC++ отладчик поддерживает стандартные (не бустовские) корутины. Во всяком случае они так заявляют.

Date: 2021-04-16 06:52 (UTC)
mopexod: (Default)
From: [personal profile] mopexod
Симулятор цифровой логики - это довольно специальный случай, пожалуй, для него стоит сделать специальную среду... Oh, wait... :)
async/await - совсем не бесплатный механизм, для него нужно сохранение состояния треда. Его абьюз - это как сумму чисел в массиве считать, разбив массив на кусочки и дав по кусочку разным тредам: в реальных ситуациях вместо одного core будут заняты все, при этом latency упадёт на порядок, lose-lose situation.

Date: 2021-04-16 06:03 (UTC)
ircicq: (Default)
From: [personal profile] ircicq
У Rust оказывается async/await идентичный C#.
Похоже современные языки сходятся к идентичной функциональности, различаясь только в синтаксисе.
Примерно как было со структурным программированием в 70-х.

Date: 2021-04-16 06:29 (UTC)