I am unable to form a mental picture of how the control flow happens with spawn.
我无法想象控制流是如何在产卵时发生的。
-
When I call
spawn(io_service, my_coroutine)
, does it add a new handler to theio_service
queue that wraps a call to themy_coroutine
?当我调用spawn(io_service, my_coroutine)时,它会向io_service队列添加一个新的处理程序来包装对my_coroutine的调用吗?
-
When inside the coroutine I call an async function passing it my
yield_context
, does it suspend the coroutine until the async operation completes?当我在coroutine中调用一个异步函数并将其传递给我的yield_context时,它是否在异步操作完成之前暂停该coroutine ?
void my_coroutine(yield_context yield) { ... async_foo(params ..., yield); ... // control comes here only once the async_foo operation completes }
What I don't understand is how we avoid waits. Say if my_coroutine
serves a TCP connection, how are other instances of my_coroutine
invoked while on particular instance is suspended, waiting for async_foo
to complete?
我不明白的是我们如何避免等待。例如,如果my_coroutine服务于TCP连接,当在特定实例上挂起等待async_foo完成时,如何调用my_coroutine的其他实例?
1 个解决方案
#1
19
In short:
简而言之:
- When
spawn()
is invoked, Boost.Asio performs some setup work and then will use astrand
todispatch()
an internal handler that creates a coroutine using the user provided function as an entry point. Under certain conditions, the internal handler can be will be invoked within the call tospawn()
, and other times it will be posted to theio_service
for deferred invocation. - 调用spawn()时,使用Boost。Asio执行一些设置工作,然后使用一个链来分派()一个内部处理程序,它使用用户提供的函数作为入口点创建一个coroutine。在某些条件下,可以在调用中调用内部处理程序来spawn(),而在其他时候,它将被发送到io_service以进行延迟调用。
- The coroutine is suspended until either the operation completes and the completion handler is invoked, the
io_service
is destroyed, or Boost.Asio detects that the coroutine has been suspended with no way to resume it, at which point Boost.Asio will destroy the coroutine. - coroutine将被挂起,直到操作完成并调用完成处理程序、销毁io_service或Boost为止。Asio检测到警戒线已被暂停,无法恢复,此时Boost。阿西奥会摧毁警戒线。
As mentioned above, when spawn()
is invoked, Boost.Asio performs some setup work and then will use a strand
to dispatch()
an internal handler that creates a coroutine using the user provided function as an entry point. When the yield_context
object is passed as a handler to asynchronous operations, Boost.Asio will yield immediately after initiating the asynchronous operation with a completion handler that will copy results and resume the coroutine. The previously mentioned strand is owned by the coroutine is used to guarantee the yield occurs before resume. Lets consider a simple example demonstrating spawn()
:
如上所述,在调用spawn()时,使用Boost。Asio执行一些设置工作,然后使用一个链来分派()一个内部处理程序,它使用用户提供的函数作为入口点创建一个coroutine。当producd_context对象作为处理程序传递给异步操作时,Boost。Asio将在初始化异步操作后立即产生一个完成处理程序,该处理程序将复制结果并恢复coroutine。前文所述的链为coroutine所有,用于保证产量在恢复前发生。让我们考虑一个演示spawn()的简单示例:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
boost::asio::io_service io_service;
void other_work()
{
std::cout << "Other work" << std::endl;
}
void my_work(boost::asio::yield_context yield_context)
{
// Add more work to the io_service.
io_service.post(&other_work);
// Wait on a timer within the coroutine.
boost::asio::deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::seconds(1));
std::cout << "Start wait" << std::endl;
timer.async_wait(yield_context);
std::cout << "Woke up" << std::endl;
}
int main ()
{
boost::asio::spawn(io_service, &my_work);
io_service.run();
}
The above example outputs:
上面的示例输出:
Start wait
Other work
Woke up
Here is an attempt to illustrate the execution of the example. Paths in |
indicate the active stack, :
indicates the suspended stack, and arrows are used to indicate transfer of control:
这里尝试说明示例的执行情况。|中的路径表示活动堆栈:表示挂起堆栈,箭头表示控制转移:
boost::asio::io_service io_service;
boost::asio::spawn(io_service, &my_work);
`-- dispatch a coroutine creator
into the io_service.
io_service.run();
|-- invoke the coroutine creator
| handler.
| |-- create and jump into
| | into coroutine ----> my_work()
: : |-- post &other_work onto
: : | the io_service
: : |-- create timer
: : |-- set timer expiration
: : |-- cout << "Start wait" << endl;
: : |-- timer.async_wait(yield)
: : | |-- create error_code on stack
: : | |-- initiate async_wait operation,
: : | | passing in completion handler that
: : | | will resume the coroutine
| `-- return <---- | |-- yield
|-- io_service has work (the : :
| &other_work and async_wait) : :
|-- invoke other_work() : :
| `-- cout << "Other work" : :
| << endl; : :
|-- io_service still has work : :
| (the async_wait operation) : :
| ...async wait completes... : :
|-- invoke completion handler : :
| |-- copies error_code : :
| | provided by service : :
| | into the one on the : :
| | coroutine stack : :
| |-- resume ----> | `-- return error code
: : |-- cout << "Woke up." << endl;
: : |-- exiting my_work block, timer is
: : | destroyed.
| `-- return <---- `-- coroutine done, yielding
`-- no outstanding work in
io_service, return.
#1
19
In short:
简而言之:
- When
spawn()
is invoked, Boost.Asio performs some setup work and then will use astrand
todispatch()
an internal handler that creates a coroutine using the user provided function as an entry point. Under certain conditions, the internal handler can be will be invoked within the call tospawn()
, and other times it will be posted to theio_service
for deferred invocation. - 调用spawn()时,使用Boost。Asio执行一些设置工作,然后使用一个链来分派()一个内部处理程序,它使用用户提供的函数作为入口点创建一个coroutine。在某些条件下,可以在调用中调用内部处理程序来spawn(),而在其他时候,它将被发送到io_service以进行延迟调用。
- The coroutine is suspended until either the operation completes and the completion handler is invoked, the
io_service
is destroyed, or Boost.Asio detects that the coroutine has been suspended with no way to resume it, at which point Boost.Asio will destroy the coroutine. - coroutine将被挂起,直到操作完成并调用完成处理程序、销毁io_service或Boost为止。Asio检测到警戒线已被暂停,无法恢复,此时Boost。阿西奥会摧毁警戒线。
As mentioned above, when spawn()
is invoked, Boost.Asio performs some setup work and then will use a strand
to dispatch()
an internal handler that creates a coroutine using the user provided function as an entry point. When the yield_context
object is passed as a handler to asynchronous operations, Boost.Asio will yield immediately after initiating the asynchronous operation with a completion handler that will copy results and resume the coroutine. The previously mentioned strand is owned by the coroutine is used to guarantee the yield occurs before resume. Lets consider a simple example demonstrating spawn()
:
如上所述,在调用spawn()时,使用Boost。Asio执行一些设置工作,然后使用一个链来分派()一个内部处理程序,它使用用户提供的函数作为入口点创建一个coroutine。当producd_context对象作为处理程序传递给异步操作时,Boost。Asio将在初始化异步操作后立即产生一个完成处理程序,该处理程序将复制结果并恢复coroutine。前文所述的链为coroutine所有,用于保证产量在恢复前发生。让我们考虑一个演示spawn()的简单示例:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
boost::asio::io_service io_service;
void other_work()
{
std::cout << "Other work" << std::endl;
}
void my_work(boost::asio::yield_context yield_context)
{
// Add more work to the io_service.
io_service.post(&other_work);
// Wait on a timer within the coroutine.
boost::asio::deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::seconds(1));
std::cout << "Start wait" << std::endl;
timer.async_wait(yield_context);
std::cout << "Woke up" << std::endl;
}
int main ()
{
boost::asio::spawn(io_service, &my_work);
io_service.run();
}
The above example outputs:
上面的示例输出:
Start wait
Other work
Woke up
Here is an attempt to illustrate the execution of the example. Paths in |
indicate the active stack, :
indicates the suspended stack, and arrows are used to indicate transfer of control:
这里尝试说明示例的执行情况。|中的路径表示活动堆栈:表示挂起堆栈,箭头表示控制转移:
boost::asio::io_service io_service;
boost::asio::spawn(io_service, &my_work);
`-- dispatch a coroutine creator
into the io_service.
io_service.run();
|-- invoke the coroutine creator
| handler.
| |-- create and jump into
| | into coroutine ----> my_work()
: : |-- post &other_work onto
: : | the io_service
: : |-- create timer
: : |-- set timer expiration
: : |-- cout << "Start wait" << endl;
: : |-- timer.async_wait(yield)
: : | |-- create error_code on stack
: : | |-- initiate async_wait operation,
: : | | passing in completion handler that
: : | | will resume the coroutine
| `-- return <---- | |-- yield
|-- io_service has work (the : :
| &other_work and async_wait) : :
|-- invoke other_work() : :
| `-- cout << "Other work" : :
| << endl; : :
|-- io_service still has work : :
| (the async_wait operation) : :
| ...async wait completes... : :
|-- invoke completion handler : :
| |-- copies error_code : :
| | provided by service : :
| | into the one on the : :
| | coroutine stack : :
| |-- resume ----> | `-- return error code
: : |-- cout << "Woke up." << endl;
: : |-- exiting my_work block, timer is
: : | destroyed.
| `-- return <---- `-- coroutine done, yielding
`-- no outstanding work in
io_service, return.