在协程执行之间强制休眠
Enforce sleep between coroutine executions
我目前有一些同步 C++ 代码,它们以顺序方式执行一些耗时的任务。我正在考虑使用 Boost 协程将其重构为并行任务。
任务的核心是调用外部库,该库提供同步 API(当前正在使用)或必须定期轮询两者的异步 API推进行动并确定它是否已经完成。 API 不是线程安全的,但如果使用异步版本,只要不同时调用轮询 API 本身,它就可以应对并发发生的多个请求。
(因为我不想要任何线程转移,看来我应该直接使用协程 API 而不是使用 ASIO 包装器或类似的东西,但我愿意被说服。我我现在也在使用 Boost 1.55,所以 Fiber 库不可用;但对于这种用法来说,它似乎也有点矫枉过正。)
目前我对协程的主要问题是我不确定如何在轮询上实施节流——假设我有 100 个任务并行 运行;我希望它对所有 100 个任务进行一次轮询 运行,然后让线程休眠指定的时间。有些任务可能比其他任务完成得更快,因此稍后它可能仍会在每个循环中轮询 40 个任务,然后休眠相同的时间。我不希望它在没有中间睡眠的情况下连续两次轮询同一个任务。
好的,事实证明比我想象的要容易得多。这是我到目前为止的结果:
typedef boost::coroutines::coroutine<void>::push_type coroutine;
typedef boost::coroutines::coroutine<void>::pull_type yield_context;
typedef std::vector<coroutine> coroutine_list;
bool run_once_all(coroutine_list& coros)
{
bool pending = false;
for (auto& coro : coros)
{
if (coro)
{
coro();
pending = pending || !coro.empty();
}
}
return pending;
}
void run_all(coroutine_list& coros,
const boost::chrono::nanoseconds& idle_ns)
{
while (run_once_all(coros))
{
boost::this_thread::sleep_for(idle_ns);
}
}
void run_all(coroutine_list& coros, yield_context& yield)
{
while (run_once_all(coros))
{
yield();
}
}
您的想法是创建一个 coroutine_list
,然后 emplace_back
具有签名 void (yield_context&)
的 lambda 函数,然后 run_all
。第一个用于顶层,第二个用于嵌套协程。
似乎有效,虽然我还没有给它一个主要的锻炼。其实有点惊讶图书馆里还没有这样的东西。
我目前有一些同步 C++ 代码,它们以顺序方式执行一些耗时的任务。我正在考虑使用 Boost 协程将其重构为并行任务。
任务的核心是调用外部库,该库提供同步 API(当前正在使用)或必须定期轮询两者的异步 API推进行动并确定它是否已经完成。 API 不是线程安全的,但如果使用异步版本,只要不同时调用轮询 API 本身,它就可以应对并发发生的多个请求。
(因为我不想要任何线程转移,看来我应该直接使用协程 API 而不是使用 ASIO 包装器或类似的东西,但我愿意被说服。我我现在也在使用 Boost 1.55,所以 Fiber 库不可用;但对于这种用法来说,它似乎也有点矫枉过正。)
目前我对协程的主要问题是我不确定如何在轮询上实施节流——假设我有 100 个任务并行 运行;我希望它对所有 100 个任务进行一次轮询 运行,然后让线程休眠指定的时间。有些任务可能比其他任务完成得更快,因此稍后它可能仍会在每个循环中轮询 40 个任务,然后休眠相同的时间。我不希望它在没有中间睡眠的情况下连续两次轮询同一个任务。
好的,事实证明比我想象的要容易得多。这是我到目前为止的结果:
typedef boost::coroutines::coroutine<void>::push_type coroutine;
typedef boost::coroutines::coroutine<void>::pull_type yield_context;
typedef std::vector<coroutine> coroutine_list;
bool run_once_all(coroutine_list& coros)
{
bool pending = false;
for (auto& coro : coros)
{
if (coro)
{
coro();
pending = pending || !coro.empty();
}
}
return pending;
}
void run_all(coroutine_list& coros,
const boost::chrono::nanoseconds& idle_ns)
{
while (run_once_all(coros))
{
boost::this_thread::sleep_for(idle_ns);
}
}
void run_all(coroutine_list& coros, yield_context& yield)
{
while (run_once_all(coros))
{
yield();
}
}
您的想法是创建一个 coroutine_list
,然后 emplace_back
具有签名 void (yield_context&)
的 lambda 函数,然后 run_all
。第一个用于顶层,第二个用于嵌套协程。
似乎有效,虽然我还没有给它一个主要的锻炼。其实有点惊讶图书馆里还没有这样的东西。