cppcoro::task异步原理、非阻塞性疑问及异步并发IO实现问询
cppcoro::task 惰性执行与异步并发的核心疑问
根据cppcoro文档定义,cppcoro::task是惰性执行的异步计算——调用协程函数仅创建task对象,直到co_await时才启动协程。结合提供的示例代码,这里有两个关键问题:
- 这种延迟执行为何不等同于普通阻塞IO?
- 如何编写代码使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
相关产品推荐
相关产品推荐

