boost::asio::steady_timer t(svc, boost::asio::chrono::seconds(45));
// this function returns immediately and make new thread
Нет, это не создает новую тему. Он просто создает сервисный объект (таймер) и возвращает. очевидно сразу, как std::string s("hello");
возвращается при построении строки.
t.async_wait(&print);
// this function returns immediately>>>>also it adds 1 out standing work to
// svc. is async_wait body runned in main threaed OR in another thread????if
// it is ran in another thread,how immediate return happens"not
// blocking"??why async_meaning is not returning immediately like
// async_wait?
Замедление.
это async_wait
тело, запущенное в основном потоке ИЛИ в другом потоке?
Это просто функция. Он работает в текущем потоке. Например, когда вы вызывали printf
.
, если он запускается в другом потоке, как немедленный возврат происходит "не блокируя"?
Ну, это не в другом потоке , Но если бы это было так, то было бы очевидно, как он вернул бы «не блокирование»: потому что работа не выполняется в текущем потоке.
Почему async_meaning_of_life
не возвращается сразу, как async_wait
?
Возвращается немедленно.
Теперь немного хитрее: даже если вы используете его с yield_context (внутри сопрограммы). Он немедленно вернется и вызовет сопрограмму. Это означает, что другие задачи могут запускаться в служебном потоке (ах), и только после завершения операции asyn c сопрограмма будет возобновлена. С точки зрения сопрограммы, это будет выглядеть так, как если бы звонок блокировался. В этом весь смысл (стопки) сопрограмм. Он «абстрагирует» асинхронность.
Итак, да, async_meaning_of_life
всегда (всегда) возвращает (почти) немедленно.
svc.post([]() { // this adds 1 outstanding work to svc and does not start
Правильно. Используйте функцию {poll|run}[_one,_for,_until]
для запуска задач².
auto answer = async_meaning_of_life(true, asio::use_future);
std::cout << __FUNCTION__ << ": Answer: " << answer.get() << "\n";
Здесь вы ничего не спрашиваете, но использование будущего, просто чтобы дождаться его, является анти-паттерном ». Это абсолютно бесполезно, поскольку оно всегда будет генерировать блокирующее поведение.
Вы должны где-то хранить будущее, выполнять другую работу, а затем, когда вам понадобится результат будущего (а он может или не может быть уже завершен), вы ожидаете его (.get()
Вы должны хранить будущее где-нибудь, выполняйте другую работу, а затем, когда вам нужен результат будущего (а он может или не может быть уже завершен), вы ожидаете его (например, вызывая .get()
).
// using_yield_ec( yield);this is wrong usage
// using_yield_catch( yield);this is wrong usage
Правильно. При правильном использовании сервис Asio предоставит вам контекст урожайности.
// boost::asio::yield_context yield;
// 4-18-2020 this is only used with spawn ,if you want to use stakeful
// coroutines,use push and pull types of coroutine "i wonder how to do
// this???"
Не знаю. Просто обратитесь к документации Boost Coroutine (я предлагаю Boost Coroutine2). Это вне топи c для Asio asyn c операций.
// using_future();this is normal usage but it does not return immediately
// and it executes in main thread.
Ну, да. Вы взяли это из минимального примера, который показывает ТОЛЬКО механику различных токенов async_result.
Просто обратитесь к нескольким строчкам выше:
Вы должны хранить будущее где-нибудь, выполнять другую работу, а затем, когда вам нужен результат будущего (а он может или не может быть уже завершено) вы ждете его (.get()
Вы должны где-то хранить будущее, выполнять другую работу, а затем, когда вам нужен результат будущего (а он может или не может быть уже завершен), вы ожидаете его (например, вызывая .get()
).
svc.post(using_future_composed);
Опять же, я не вижу вопросов, но я не думаю, что это означает, что вы понимаете это. Я шагаю.
Я вижу, using_future_composed
в основном using_future
, но вместо этого звонит async_meaning_of_life_composed
.
Теперь, глядя на async_meaning_of_life_composed
Я понятия не имею, что он должен делать. Это похоже на async_meaning_of_life
с добавлением случайных строк кода, выполняющих все виды операций, включая операции блокировки (см. Anti-pattern¹) в функции, которая должна планировать только асинхронную операцию c.
Это просто не то, что вы хотите сделать. Когда-либо.
spawn(svc, using_yield_ec);
// this adds 2 outstanding work to svc why 2 works are made while we are
// launching one function????
Честно говоря, я не знаю. Я предполагаю, что это потому, что запуск самого coro размещен в рабочей очереди, поэтому он запускается исключительно в исключительных ситуациях из одного из рабочих потоков.
Здесь важнее то, что вы еще не запустили io-работники, см. [²] выше.
spawn(svc, using_yield_catch);
// what i think i understand about mechanism of work of spawn:spawn is
// called from main thread>>>>it is just used with coroutines taking
// yield_context as argument,spawn post function to service,spawn makes link
// between the context in which service will be ran"may be main thread or
// new thread AND the context of coroutine function ran in same thread as
// service"...
Хм, в основном, да.
// ... or may be the coroutine makes new thread in which it is
// running???" ...
Определенно нет. И Coroutines, и Asio являются устройством / средой для достижения параллелизма без необходимости многопоточности. Сопрограмма никогда не создаст тему. Asio обычно не создает какие-либо потоки (если только для реализации определенных видов сервисов на некоторых платформах не будет, но они будут деталями реализации, а ваши задачи / обработчики никогда не будут работать на таких скрытая тема).
// ... .Then when svc.run is called,svc calls task"here svc is caller
// and coroutine is callee",task is executing,yield is called as completion
// token"can we call yield outside initiating function to switch to caller
// "here caller is svc"????. then we are now in svc context which calls
// another task .....
Да. Нет, yield_context
не является порталом к другому пространственно-временному континууму.
Я не совсем уверен, что вы имеете в виду под "'yield yield", поэтому, когда вы думаете о том, чтобы вызывать его извне инициирующего функция, я бы сказал: вероятно, не делайте этого.
// t.async_wait(&using_future);wrong usage leading to error?why can not in
// use using_future function as completion callback with async_wait???
Поскольку она не удовлетворяет требованиям обработчика для steady_time::async_wait
(который должен занимать только boost::system::error_code
. Вы, возможно, имеете в виду use_future
(от Asio) вместо своего using_future
?
auto ignored_future = t.async_wait(boost::asio::use_future);
Я допускаю, что имена несколько сбивают с толку. Если это поможет, переименуйте все функции using_XYZ
в demonstration_using_XYZ
.
// spawn(svc, using_future);wrong usage as using_future is not coroutine?
Вы правильно поняли.
std::thread work([]
using_future();
using_handler();
auto answer = async_meaning_of_life(true, asio::use_future);
// this function does not return immediately and is executing in main
// thread >>>>>how can we make it behave like async_wait???? first
std::cout << __FUNCTION__ << ": Answer: " << answer.get() << "\n";
});
Полагаю, вы просто скопировали / вставили комментарий, но на случай, если вы действительно обеспокоены: нет, это не так не запускается в главном потоке. Он запускается в потоке work
, и да, это потому, что вы блокируете в future::get()
. См. выше¹.
std::thread work_io([&] { // this starts new thread in which svc is run
svc.run();
});
Лучше поздно, чем никогда :)
svc.run(); // this run svc in main thread
Правильно, и больше бегать не повредит. Запуск службы в нескольких потоках может требует синхронизации обработчика: Зачем мне нужно прядь на соединение при использовании boost :: asio?
// general question:
/*
using_* is considered normal function or coroutine OR composed operation??
Нормальный функции (см. пояснение о переименовании в demonstration_using_XYZ
выше)
async_meaning is considered initiating function?
Правильно.
why does not it return immediately when ran in main thread?
Да. Смотри выше. Если вы имеете в виду, почему ваша собственная функция async_meaning_of_life_composed
bblock? Это потому, что вы заставили его выполнять операции блокировки (см. Выше).
how can we make
it return immediately and then when certain result is present ,it calls its
callback??
Обычный способ сделать это - запустить другие операции asyn c. Скажем, например, вы ждете завершения сетевой операции (асинхронно, например, с помощью boost::asio::async_write
), а когда она закончится, вы вызываете handler
. Помощник async_result
делает так, что вам не нужно знать фактический completion_handler_type
, и он «волшебным образом» будет делать правильные вещи независимо от того, как была вызвана ваша инициирующая функция.
async_wait is considered initiating function? why does it return
immediately then when timer expires ,it calls back its completion token??
Потому что Вот как создаются операции asyn c. Они были разработаны таким образом, потому что это полезное поведение.
can i make the following composed operation:
i will make composed operation which returns future to caller thread,
and inside it i shall call another composed operation with coroutine,
*/
Вы можете запустить сопрограмму. Просто убедитесь, что вы передаете право собственности на результат async_result, чтобы можно было оттуда вызывать обработчик, чтобы сигнализировать о завершении вашей операции.
В случае фьючерсов обычный способ составления операций - это составление фьючерсов, например : https://www.boost.org/doc/libs/1_72_0/doc/html/thread/synchronization.html#thread .synchronization.futures.then
std::string someotheroperation(int);
future<int> fut1 = foo();
future<std::string> fut2 = foo().then(someotheroperation);
БОНУС
Основная часть документации по написанию составных операций с Asio (по иронии судьбы) эта страница в Зверь документация. Возможно, просмотр еще нескольких реальных примеров может дать вам больше идей.
Имейте в виду, Beast поставляется с несколькими средствами, которые делают обслуживание библиотеки для / them / немного проще, но вполне могут быть излишними для вашего собственного приложения. , Опять же, если вы ошибетесь на своем пути, вы не пропустите важные вещи, подобные тем, которые мы обсуждали здесь ранее: