当使用无栈协程在库中实现一个功能时,我们需要为该功能提供多种接口以供不同的用户的使用。 例如,我们使用无栈协程实现了一个 Read 功能。
cpp
Lazy<size_t> Read();
但调用者可能为无栈协程、有栈协程或者普通函数,由于无栈协程存在传染性,此时该如何做呢?
无栈协程
当调用者为无栈协程时,不需要额外封装,使用 co_await
调用即可:
cpp
Lazy<size_t> foo() {
auto val = co_await Read();
// ...
}
有栈协程
当调用者为有栈协程时,可以使用 await
方法封装 Read 方法。
cpp
Lazy<size_t> Read();
Future<size_t> ReadAsync() {
return await(nullptr, Read);
}
void foo() { // in Uthread
auto val = ReadAsync().get();
// ...
}
await
await 方法用于有栈协程异步等待无栈协程时。await 有以下两个重载:
Class member method
cpp
template <class B, class Fn, class C, class... Ts>
decltype(auto) await(Executor* ex, Fn B::* fn, C* cls, Ts&&... ts);
若 Fn 返回类型为 Lazy<T>
,则 await 返回值为 T。
使用场景为
cpp
class Foo {
public:
lazy<T> bar(int a, int b) {}
};
Foo f;
await(ex, &Foo::bar, &f, a, b);
其中 ex 为指定的调度器,若无可设为 nullptr。
Normal Method
cpp
template <class Fn, class... Ts>
decltype(auto) await(Executor* ex, Fn&& fn, Ts&&... ts);
若 Fn 返回类型为 Lazy<T>
,则 await 返回值为 T。
使用场景为
cpp
lazy<T> foo(Ts&&...);
await(ex, foo, Ts&&...);
auto lambda = [](Ts&&...) -> lazy<T> {
// ...
};
await(ex, lambda, Ts&&...);
其中 ex 为指定的调度器,若无可设为 nullptr。
普通函数
普通函数可以使用 syncAwait 封装无栈协程:
cpp
Lazy<size_t> Read();
size_t ReadSync() {
return syncAwait(Read());
}
void foo() {
auto val = ReadSync();
// ...
}
若需要为无栈协程指定调度器,可:
cpp
Lazy<size_t> Read();
size_t ReadSync(Executor* ex) {
return syncAwait(Read().via(ex));
}
void foo() {
auto *ex = getExecutor();
auto val = ReadSync(ex);
// ...
}
异步非阻塞调用
无论普通函数、有栈协程或者是无栈协程,都可以使用 .start
方式异步非阻塞地调用协程:
cpp
Lazy<size_t> Read();
void ReadCallback(std::function<void(Try<size_t>)> callback) {
Read().start(callback);
}
void foo() {
ReadCallback(callback);
// continue to execute immediately.
}