我正在努力学习ppl。而不是使用线程。让我们从头开始。我有这个简单的问题:
V1:
while(true)
{
auto important_msg = ReceiveImportantMessage_Blocking(); //Blocks for about 20s until there is a new message
//do processing on important_msg
auto unimportant_msg = ReceiveUnimportantMessage_Blocking(); //Blocks for about 60s until there is a new message
//do processing on unimportant_msg
}
v1显然很糟糕,因为这两个调用都会阻塞并最终等待彼此。
V2:
while(true)
{
auto important_msg = ReceiveImportantMessage_Blocking(); //Blocks for about 20s until there is a new message
//do processing on important_msg
auto unimportant_msg = CheckForUnimportantMessage_NonBlocking(); //works by polling queue. Returns empty if no message
if(unimportant_msg) {
//do processing on unimportant_msg
}
}
v2更好,因为不重要的消息不会阻止重要消息。此外,重要消息在收到后会被处理。在我们收到重要消息之前,这些不重要的消息虽然没有得到检查。因此,当我到达它时,不重要的消息可能是20岁。
V3:
while(true)
{
auto important_msg = CheckForImportantMessage_NonBlocking(); //works by polling queue. Returns empty if no message
if(important_msg) {
//do processing on important_msg
}
auto unimportant_msg = CheckForUnimportantMessage_NonBlocking(); //works by polling queue. Returns empty if no message
if(unimportant_msg) {
//do processing on unimportant_msg
}
sleep(10); //just so we don't busy wait.
}
v3更快地获得不重要的消息。但它对重要消息的速度也较慢。重要消息的处理一旦收到就不会发生。但只有当我到处检查它时。当我添加一个睡眠以避免繁忙等待(并且消耗太多的CPU时间)时,重要的消息将比v2需要更长的时间来接收和处理。
V4:
{
auto important_msg_task = ReceiveImportantMessageTask_NonBlocking(); //ppl::task
auto unimportant_msg_task = ReceiveUnimportantMessageTask_NonBlocking(); //ppl::task
while(true)
{
if(important_msg_task.is_done()) {
auto important_msg = important_msg_task.get();
//do processing on important_msg
important_msg_task = ReceiveImportantMessageTask_NonBlocking(); //listen for new message
}
if(unimportant_msg_task.is_done()) {
auto unimportant_msg = unimportant_msg_task.get();
//do processing on important_msg
unimportant_msg_task = ReceiveUnimportantMessageTask_NonBlocking(); //listen for new message
}
sleep(10); //just so we don't busy wait.
}
}
V4与v3相同。只是用ppl任务代替。它的问题是一旦接收到重要消息就不会处理。
V5) 我想要删除睡眠并使用important_msg_task"。然后"一旦收到处理就开始处理,然后"。然后"处理旧邮件后,请收听新邮件,然后" .then"处理新消息等(并对unimportant_msg_task执行相同操作)。我不知道如何在循环中完成这项工作。看来我最终将永远不断增加一系列连接任务。
那么如何使用ppl解决这个问题(或者至少没有原始线程)?
答案 0 :(得分:0)
使用这种惯用代码:
template<typename Func>
concurrency::task<void> doWhile(Func func)
{
static_assert(
std::is_same_v<decltype(func()), bool> ||
std::is_same_v<decltype(func()), concurrency::task<bool>>);
return concurrency::create_task(func)
.then([func](bool needToContinue)
{
if (needToContinue)
return doWhile(func);
return concurrency::task_from_result();
});
}
对于一个任务,您可以编写如下内容:
concurrency::task<bool> process() {
// launching initial task
auto important_msg_task = ReceiveImportantMessageTask_NonBlocking(); //ppl::task
// adding continuation with processing of the result
auto continuation = important_msg_task.then([](const Message &msg)
{
// do processing on important msg
// decide whether to continue or stop processing
return stopProcessing() ? false : true;
});
return continuation;
}
auto loop = doWhile([] {
return process();
});
使用loop.get()
等到处理完成。
要有两个并行处理的“循环”,只需为另一个“循环”触发第二个doWhile
,例如像这样:
auto loop2 = doWhile([] {
return ReceiveUnimportantMessageTask_NonBlocking()
.then([](const Message &msg)
{
//do processing on unimportant msg
return !stopProcessing();
});
});
由于所有任务都在线程池上执行,因此具有多个doWhile
可以有效地使处理并行化。