Comments 34
Благодарю за статью. Как по мне — самая лучшая вводная по корутинам. Поправь только в тексте про await_ready(), указывается дважды false как возвращаемый результат.
Теперь вот вопрос по Task. А не надо ли его сохранять? Там хэндл корутины же лежит. А что будет, если он будет уничтожен, а мы вызовем resume? А то кажется, что doSomething работает только потому, что память незакораптилась.
var client = await server.accept(); // принимаем входящее подключение
var request = await socket.read(...));
Похоже код никого не интересует. А код зачем-то приведен с подлянкой!
Куда делся client,
и зачем он вообще нужен, если он дальше не используется и откуда взялся socket
кто-нибудь может объяснить?
socket = client
это конечно самая простая версия, но только это не может быть опечаткой. Поэтому возникает вопрос: может автора код не интересует? Тогда не имеет смысла дальше анализировать страшные классы приведенные в статье.
Да всё просто же, писался код одновременно со статьёй, копировался кусками, периодически редактировался и снова кусками переносился. Вот и исправление socket на client полностью не перенеслось.
Исправить это, конечно же, надо - но вот далеко идущие выводы про "автора код не интересует" я бы делать не стал.
Вот и исправление socket на client полностью не перенеслось.
это как это? Когда могло произойти такое исправление в трех строчках, в пяти?
не верю.
что выполняя рутинные действия, когда нужно сделать множество однообразных изменений во многих местах
Как мне показалось мы говорили о 5-ти строчках которые определяют-задают смысл всей статьи, и в этих строчках допущена ошибка, именно это меня и расстроило. Я не понимаю при чем здесь "множество однообразных изменений во многих местах", я про 5-ть строчек говорю, а вы про что?
Но честно говоря даже общий смысл статьи по моему ускальзает, потому что:
"WTF? Серьезно? Почему ТАК сложно? Зачем столько танцев с бубном чтобы запустить простейшие корутины?!"
Начать с того что я бы не стал так безапеляционно совмещать слова "корутины" и "простейшие". Вы сами показали что все действительно очень сложно, а главное совсем не понятно, что же вы сравнивали на самом деле.
Кроме модного слова "корутины" и некоторого непонятного шаманства вокруг него в статье нет ничего полезного для "чайника", которому она предназначена, судя по названию. ИМХО.
Мне просто интересно на чем основано восхищение тех кто вашу статью плюсует, поэтому я и указал на ошибку публично. Раз с поддержкой у вас проблем нет, я думаю критика вам не помешает, а то как бы корона не вросла и не повредила что-то в голове.
Можно просто нажать Ctrl+Enter, чтобы сообщить автору об опечатке
Разве select и poll -- это асинхронный ввод-вывод, а не неблокирующий? Я не линухоид, поэтому и спрашиваю. Просто неблокирующий к асинхронщине отношения не имеет и толку с него в этом плане примерно нуль (смысл асинхронного ввода-вывода, как правильно указано в статье, -- сообщать о завершении операции ввода-вывода, ну а неблокирующий лишь говорит о том, что файл готов к дальнейшей работе -- а, скажем, настоящий честный дисковый файл всегда готов).
так и не понял почему метод с корутинами отличается от метода рассматриваемого в начале статьи и где говорится, что можно создать потоки для задания... По сути оно одно и тоже получается, только меньше кода самописного...
Спасибо за статью, она действительно закрыла некоторые пробелы в понимании но если честно с момента рассказа Гор Нишанова про корутины когда их ещё только пропихивали в стандарт, году в 18 на одном из открытых мероприятий яндекса, и посмотрев уже не один доклад по корутинам на cpp russia и cppcon, я пока ментально видимо не готов к корутинам и не могу принять то чем они проще. На "бумаге" все выглядит вроде не плохо, а потом начинается десяток всяких мета классов для того чтоб это работало с не очевидным и не до конца понятными переходами между состояниями и когда начинаю задумываться, а что если где то что то пойдёт не так и возникнет какая то гонка то я умру это дебажить. Для меня код из "старых" плюсов выглядит максимально просто и понятно, я понимаю примерные места где может быть гонка и мне понятно как это отлаживать в случае проблем, а вот корутины мне уже начинают boost asio напоминать и вспоминая дни отладки там бросает в дрож..
Что-то я не совсем понимаю или совсем не понимаю. doSomething() вызывает две функции с co_await .... Я так понимаю пока одна не закончится следующая не будет вызвана. А где же асинхронность? Можно какой-нибудь пример где два request выполняются наперегонки и печатают результат когда он будет доступен.
Спасибо. Получается что вся кухня с callback и select никуда не делась, а работает себе в отдельном потоке, а в основном потоке что-то типа красивой обёртки - пользовательский интерфейс где можно выполнять высокоуровневые операции. Преимущество как мне кажется, что количество callback в коде будет значительно меньше. В данном случае будет только один :) Но если нужно добавить что-то другое помимо curl, то нужен либо отдельный поток, либо добавить это в WebClient::runLoop(). Я правильно понимаю? Например асинхронное чтения файла или server.accept(). Как бы вы поступили для такого расширения этого кода?
Получается что вся кухня с callback и select никуда не делась, а работает себе в отдельном потоке, а в основном потоке что-то типа красивой обёртки
Нет, не получается. Тот поток, который исполняет цикл событий - это и есть основной.
Но если нужно добавить что-то другое помимо curl, то нужен либо отдельный поток, либо добавить это в WebClient::runLoop()
В целом, да. Для каждого цикла обработки событий нужен свой поток (а лучше набор потоков по числу ядер).
Хотя конкретно в случае асинхронных сокетов и асинхронных http-запросов проще отказаться от curl и использовать только сокеты.
правильно написал @mayorovp
Хотя конкретно в случае асинхронных сокетов и асинхронных http-запросов проще отказаться от curl и использовать только сокеты.
в интерфейсах к сокетам есть все что нужно для ассинхронности, приплетать там какие-то "корутины" для которых даже нет однозначного определения (если вы попробуете посмотреть кто что понимает под этим названием) да еще и с непонятной внешней библиотекой в стабильности которой еще надо убедиться, совершенно не к чему.
У меня когда-то было решение как раз такой задачки с которой начал автор, она решается с использованием двух потоков достаточно просто, если вы умеете писать решения с асинхронностью на потоках, а если не умеете, то корутины вам точно не помогут.
Может быть я как-нибудь напишу статью про это решение, раз уж мне напомнили задачку и теперь она у меня снова перед глазами как 17 лет назад.
Вроде понятно. Я просто раньше думал что можно обойтись и без второго потока. Каким-то образом жонглировать в единственном потоке всеми состояниями и переключать контекст по мере того как становятся доступными данные. А внутри под капотом select/epoll + файловые дескрипторы ну или CURL. Такое возможно? Скажем вызываешь co_await а там начинает шуршать вся эта машина состояний и возможно выполнится какой-то другой co_await из другого контекста и там пойдёт выполнение дальше...
"больные ублюдки" - вот что я понял про с++
На всех других языках это пишется в пару строк
Мы в мире C++ с юности привыкли к боли и унижениям
в каком-то грустном мире вы живете. Мы в нашем С++ мире привыкли к неограниченным возможностям, правда это было еще до 2011 года. Видимо это с 2011 года вас загоняют в мир боли и унижений. Это печально.
вряд ли вам поможет C++11 или даже C++115, когда вы не понимаете, что так писать нельзя:
var socket = await server.accept(); // принимаем входящее подключение
var request = await socket.read(...));
var result = await db_сient.do_query(transform_request(request));
await socket.write(transform_result(result));
socket.close();
Компилятор сделает особую магию.
Вы заблокировали сервер, никакая магия вам не поможет! В течении времени работы с полученным сокетом, сервер не принимает другие входящие сокеты, не важно есть у вас там await
-ы или нет.
Корутины C++ для чайников: пишем асинхронный веб-клиент