[英]boost asio, yield an awaitable function
I have several time-consuming computation jobs, which shall not block the executing thread while executing.我有几个耗时的计算作业,它们在执行时不会阻塞正在执行的线程。 I also want to use c++20 coroutines +
asio::awaitable
's to accomplish this.我也想使用 c++20 coroutines +
asio::awaitable
来完成这个。 The asio::io_context
's thread for example should still be responsive.例如
asio::io_context
的线程应该仍然是响应式的。 Therefore, I want my Job to suspend/yield after some time, and then continue its own execution, when the executioner does not have other jobs to do.因此,当刽子手没有其他工作要做时,我希望我的工作在一段时间后暂停/屈服,然后继续自己的执行。 Also, here are other coroutines with want to await the result of the computations (1:n relation.).
此外,这里还有其他想要等待计算结果的协程(1:n 关系)。
What is the best (nearly no overhead due to timers for example) way to achieve this with boost::asio?使用 boost::asio 实现这一目标的最佳方法是什么(例如,由于计时器几乎没有开销)? Other coro libraries support something like events.
其他 coro 库支持事件之类的东西。
Here is a code snippet to show my intention:这是一个代码片段来显示我的意图:
MyReturnType result;
CoroEvent coro_event;
auto long_func(asio::ExecutionCtx ctx) -> awaitable<void> {
for (size_t i{}; i < 1000){
for (size_t j{}; i < 1000){
result.compute(i*1000+j);
}
ctx.yield();
}
coro_event.send();
co_return;
}
auto get_job_value() -> awaitable<MyReturnType> {
co_await coro_event.async_wait(use_awaitable); // continues if done, suspends if not.
co_return result;
}
You can use timers, they are lightweight.您可以使用计时器,它们是轻量级的。
Eg例如
struct CoroEvent {
using C = asio::steady_timer::clock_type;
using T = C::time_point;
void send() { _timer.expires_at(T::min()); }
auto async_wait(auto&& token) {
return _timer.async_wait(std::forward<decltype(token)>(token));
}
asio::steady_timer _timer{asio::system_executor{}, T::max()};
};
#include <boost/asio.hpp>
#include <coroutine>
#include <iostream>
namespace asio = boost::asio;
using asio::use_awaitable;
using asio::awaitable;
struct MyReturnType {
void compute(size_t v) { counter += v; }
intmax_t counter = 0;
} result;
struct CoroEvent {
using C = asio::steady_timer::clock_type;
using T = C::time_point;
void send() { _timer.expires_at(T::min()); }
auto async_wait(auto&& token) {
return _timer.async_wait(std::forward<decltype(token)>(token));
}
asio::steady_timer _timer{asio::system_executor{}, T::max()};
} coro_event;
awaitable<void> long_func() {
for (size_t i = 0; i < 1'000; ++i) {
for (size_t j = 0; j < 1'000; ++j) {
result.compute(i * 1'000 + j);
}
// co_await std::suspend_always{};
}
coro_event.send();
co_return;
}
awaitable<MyReturnType> get_job_value() {
co_await coro_event.async_wait(
use_awaitable); // continues if done, suspends if not.
co_return result;
}
awaitable<void> consumer(int id, auto output_executor) {
auto r = co_await get_job_value();
// synchronize output to prevent a mess
post(output_executor, [id, sum = r.counter] {
std::cout << "Received in consumer #" << id << ": " << sum << std::endl;
});
co_return;
}
int main() {
asio::thread_pool ioc;
asio::co_spawn(ioc, long_func(), asio::detached);
auto output = make_strand(ioc);
for (int id = 1; id < 10; ++id)
asio::co_spawn(ioc, consumer(id, output), asio::detached);
ioc.join();
}
Prints eg打印例如
Received in consumer #2: 499999500000
Received in consumer #3: 499999500000
Received in consumer #5: 499999500000
Received in consumer #6: 499999500000
Received in consumer #4: 499999500000
Received in consumer #7: 499999500000
Received in consumer #9: 499999500000
Received in consumer #1: 499999500000
Received in consumer #8: 499999500000
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.