You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

cppcoro::task异步原理、非阻塞性疑问及异步并发IO实现问询

cppcoro::task 惰性执行与异步并发的核心疑问

根据cppcoro文档定义,cppcoro::task是惰性执行的异步计算——调用协程函数仅创建task对象,直到co_await时才启动协程。结合提供的示例代码,这里有两个关键问题:

  1. 这种延迟执行为何不等同于普通阻塞IO?
  2. 如何编写代码使IO函数真正异步并发执行?

示例代码

#include <cppcoro/read_only_file.hpp>
#include <cppcoro/task.hpp>

cppcoro::task<int> count_lines(std::string path)
{
  auto file = co_await cppcoro::read_only_file::open(path);

  int lineCount = 0;

  char buffer[1024];
  size_t bytesRead;
  std::uint64_t offset = 0;
  do
  {
    bytesRead = co_await file.read(offset, buffer, sizeof(buffer));
    lineCount += std::count(buffer, buffer + bytesRead, '\n');
    offset += bytesRead;
  } while (bytesRead > 0);

  co_return lineCount;
}

cppcoro::task<> usage_example()
{
  // Calling function creates a new task but doesn't start
  // executing the coroutine yet.
  cppcoro::task<int> countTask = count_lines("foo.txt");

  // ...

  // Coroutine is only started when we later co_await the task.
  int lineCount = co_await countTask;

  std::cout << "line count = " << lineCount << std::endl;
}

问题1:延迟执行为何不等同于普通阻塞IO?

惰性启动只是协程的启动时机延迟,但协程内部的IO操作是异步非阻塞的,和普通阻塞IO有本质区别:

  • 普通阻塞IO:调用阻塞IO函数时,当前线程会被挂起,直到IO操作完成,期间线程无法处理任何其他任务。
  • cppcoro协程的异步IO:当co_await某个异步操作(比如file.read())时,协程会暂停执行并让出当前线程,线程可以立即去处理其他任务(比如其他协程的执行)。当IO操作完成后,协程会在合适的时机恢复执行,整个过程中线程不会被闲置。

哪怕是延迟到co_await才启动协程,启动后的IO操作依然是异步的,不会阻塞线程——这和阻塞IO的线程挂起完全是两回事。

问题2:如何实现IO函数的异步并发执行?

要让多个IO任务并发执行,需要创建多个cppcoro::task对象,然后同时等待它们完成。cppcoro提供了cppcoro::when_all工具来实现这一点,它可以等待多个task并行执行。

并发执行示例代码

#include <cppcoro/read_only_file.hpp>
#include <cppcoro/task.hpp>
#include <cppcoro/when_all.hpp>
#include <vector>
#include <string>

cppcoro::task<int> count_lines(std::string path)
{
  auto file = co_await cppcoro::read_only_file::open(path);

  int lineCount = 0;
  char buffer[1024];
  size_t bytesRead;
  std::uint64_t offset = 0;
  do
  {
    bytesRead = co_await file.read(offset, buffer, sizeof(buffer));
    lineCount += std::count(buffer, buffer + bytesRead, '\n');
    offset += bytesRead;
  } while (bytesRead > 0);

  co_return lineCount;
}

cppcoro::task<> concurrent_usage_example()
{
  // 创建多个task(此时都未启动)
  auto task1 = count_lines("foo.txt");
  auto task2 = count_lines("bar.txt");
  auto task3 = count_lines("baz.txt");

  // 同时await所有task,此时所有协程启动并并发执行
  auto results = co_await cppcoro::when_all(std::move(task1), std::move(task2), std::move(task3));

  // 分别获取每个任务的结果
  int count1 = std::get<0>(results);
  int count2 = std::get<1>(results);
  int count3 = std::get<2>(results);

  std::cout << "foo.txt lines: " << count1 << "\n";
  std::cout << "bar.txt lines: " << count2 << "\n";
  std::cout << "baz.txt lines: " << count3 << "\n";
}

关键说明

  • 当调用co_await cppcoro::when_all(...)时,所有传入的task会被同时启动,各自的异步IO操作会并行进行。
  • 每个协程在遇到co_await时都会让出线程,所以线程可以在多个协程的IO等待间隙处理其他任务,实现真正的并发,而不会像阻塞IO那样线程被逐个占用。

内容的提问来源于stack exchange,提问作者Pibben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 12:43:20