BUzer
> чтобы использовать корутину как аналог стейт-машины
Нет. Только как функцию которая не хранит каких либо состояний, но может конечно влиять на внешнее состояние объекта в виде транзакции, по сути сейв это дождаться всех комитов и не давать больше открывать новые транзакции, ессно что транзакция не должна быть дольше одной секунды.
gamedevfor
Если не давать создавать новые, но ждать совершения старых, то сейв будет влиять на геймплей. Условно: приказали юнитам стрелять, нажали сейв - игра будет ждать пока все наши юниты выстрелят, а противник в ответ стрелять не сможет.
kipar
Ессно что нужно выбрать дискретность для игры и подгонять корутины уже под эту дискретность.
ronniko
> И на 12 ядерном проце в 24 потока, как-то корутины не особо нужны и
> впечатляют.
> Это мое мнение.
По мегабайту адресного пространства на каждую и с провалом в ядро на каждое переключение контекста впечатляют достаточно сильно, чтобы задумываться об альтернативных способах имплементации параллелизма. Сопрограммы, таки, и есть эта самая альтернатива, и её профитность по сравнению с прочими альтернативами в том, что программирование под них максимально похоже на синхронное программирование под обычные потоки.
По мегабайту адресного пространства на каждую и с провалом в ядро на каждое переключение
По мегабайту адресного пространства для стека.
Память можно резервировать хоть по два гига на ядро.
С провалом в ядро на каждое переключение это еще надо постараться.
По твоему в Вулкане и Directx 12 сделали треды, что бы было больше провалов и тормозов ? :)
Короче, суть корутин в С++ - это ускорить std::this_thread::yield().
Я ничего не пропустил?
Имбирная Ведьмочка
> this_thread::yield()
Там не на 100% происходит переключение потоков, так что нет.
Суть корутин в С++ - это вот тебе поддержка в компиляторе, делай с ними что захочешь и как хочешь.
Я за день добавил их поверх своего тредпула и пока все, в андроиде вроде не поддерживаются пока что.
/A\
> Я за день добавил их поверх своего тредпула
Ну то есть используешь их как ускоренный аналог std::this_thread::yield(), разве нет?
/A\
> Там не на 100% происходит переключение потоков
Я говорю про использование, а не про реализацию.
Скажем так, если взять твой код, все твои таски оставить как есть, но под капотом вместо корутин использовать настоящие потоки - всё сломается или продолжит работать как было (но, возможно, на более низкой скорости)?
Имбирная Ведьмочка
В общем да. Корутины это тоже самое что потоки, а потоки тоже самое что однопоточное выполнение)
Что стоит добавить в продолжение?
Пример системы тасков с многопоточкой сделал.
Асинхронное чтение файла?
Сеть?
Что-то из геймплея, типа "сделай действие, подожди 5 сек, сделай другое" ?
Могу еще синхронизации с ГПУ на корутинах, но там слишком много кода.
/A\
В хаскеле есть библиотека conduit для поточной обработки всего на свете.
Кондьюит - это программный код, который внутри себя может вызывать функции:
yield :: out -> Conduit in out ()
Передаёт элемент на выход кондьюиьта и приостанавливает его.
await :: Conduit in out in
Приостанавливает кондьюит в ожидании элемента на входе, как только получит - вернёт его внутреннему коду кондьюита в качестве результата.
В целом, кондьюит - это что-то общее между функциями и потоками. Подобно функции, у кондьюита могут быть начальные аргументы и конечный результат. Однако, в промежутке между ними кондьюит ещё может запрашивать произвольное количество входных элементов и выдавать произвольное количество выходных.
Кондьюиты можно соединять вход-к-выходу, как линуксовые тулзы в пайполапше:
pipe :: Conduit in mid final -> Conduit mid out final -> Conduit in out final
await в правом кондьюите передаст управление в левый до первого yield, после которого правый получит этот элемент на вход и продолжит работу. Наружу остаются торчать await из левого и yield из правого. Если один из кондьюитов-компонентов заканчивает работу и выходит, то кондьюит-склейка тоже немедленно выходит. То есть, есть, если левый кондьюит завершится - правый в await вместо результата получит прерывание, а если правый завершится - то левый прервётся на yield.
В принципе, программа на кондьюитах - она как раз похожа на юниксовый пайплайн, в котором несколько программ работают параллельно, передавая друг другу данные через стдин и стдаут. Только в кондьюитах - кондьюиты работают по очереди, а не одновременно (будучи корутинами), а в пайпах передаются не сырые байты, а программные объекты.
Генератор на пайтоне - это как кондьюит без входа.
Есть ещё корутины в луа - они почти что кондьюиты и есть, только без типизации, и без разделения между "горизонтальной" передачей (await/yield) и "вертикальной" (начальные аргументы и конечный результат).
Имбирная Ведьмочка
Ок, но к чему это все?
На С++ корутины как напишешь так они и будут работать, логику определяет программист, а сам язык дает только функцию с механизмом прерывания.
Можно повтоить подход из любого другого языка, разве что стакфул корутин нет.
/A\
> Ок, но к чему это все?
Ну так пример в продолжение же.
То, что ты там перечислил - это всё вариации на тему "делаем задачу и параллельно занимаемся другими делами", а то, что я предлагаю - это принципиально другая (ортогональная) парадигма, в которой ты оперируешь не одноразовыми задачами, а долгоживущими потоками. Если уж делать примеры, то лучше сделать несколько на совершенно разные применения в разных областях, чем по 10 раз повторять одно и то же с модами на текстурки, разве нет?
Имбирная Ведьмочка
Напиши словами что делает код на хаскеле, а то я мог не так понять.
Вроде все это делается через цикл внутри корутины.
Тема в архиве.
Рекомендуем компанию-склад t.me |