增强asio,产生一个有用的函数



我有几个耗时的计算工作,在执行时不会阻塞执行线程。我还想使用c++20协同程序+asio::awaitable来实现这一点。例如,asio::io_context的线程应该仍然有响应。因此,我希望我的工作在一段时间后暂停/屈服,然后在刽子手没有其他工作要做的时候继续自己的执行。此外,这里还有其他需要等待计算结果的协同程序(1:n关系!(。

用boost::asio实现这一目标的最佳方式是什么(例如,由于定时器的原因,几乎没有开销(?其他coro库支持类似事件的功能。

这里有一个代码片段来表明我的意图:

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;
}

您可以使用定时器,它们是轻量级的。

例如

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()};
};

在Coliru上直播

#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();
}

打印,例如

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

最新更新