c++ - C++:如何正确使用#include <协程>中可用的generator <>,task <>和lazy <>类?

标签 c++ boost-asio c++20 c++-coroutine

我从here收集到,协程类型大致分为3类:

generator<> , task<>, and lazy<>


我的问题是:如果要确定返回类型,这三者之间有什么区别?
例如:延迟加载一组文件处理程序的协同例程的返回类是什么?我的实现将使用task<FileHandler>generator<Filehandler>实现相同目的。
我已经在“执行”部分下查看了this,以了解promise object与协程进行交互时的限制。但是我只能找到实现上的差异,而不是方法上的差异。

最佳答案

我做了一些研究,我相信答案如下:
首先,C++中没有lazy<>类。 https://en.cppreference.com/w/cpp/language/coroutines错了。 (请参阅草稿进行确认)
因此,这是generator<T>task<T>的返回类型之间区别的问题。
TLDR;
最容易记住的方法是:

generators are associated with co_yield; whereas, tasks are associated with co_await


生成器
与generator类关联的co_yield机制与我们在python(请参阅文档)中会遇到的机制完全相同,并且与操作系统机制中的thread_suspend概念非常相似。
您可以选择同步或异步实现。 (有关示例,请引用cppcoro library。)
生成器类型(种类)如下所示:
struct generator {
  struct promise_type;
  using handle = std::coroutine_handle<promise_type>;
  struct promise_type {
    int current_value;
    static auto get_return_object_on_allocation_failure() { return generator{nullptr}; }
    auto get_return_object() { return generator{handle::from_promise(*this)}; }
    auto initial_suspend() { return std::suspend_always{}; }
    auto final_suspend() noexcept { return std::suspend_always{}; }
    void unhandled_exception() { std::terminate(); }
    void return_void() {}
    auto yield_value(int value) {
      current_value = value;
      return std::suspend_always{};
    }
  };
  bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }
  int current_value() { return coro.promise().current_value; }
  generator(generator const&) = delete;
  generator(generator && rhs) : coro(rhs.coro) { rhs.coro = nullptr; }
  ~generator() { if (coro) coro.destroy(); }
private:
  generator(handle h) : coro(h) {}
  handle coro;
};
您将按以下方式使用生成器类型:
generator f() { co_yield 1; co_yield 2; }
任务
另一方面,任务与co_await表达式关联。它需要Awaitable<T>Awaiter<T>概念,因此请确保您正确使用与这两个概念相关的约束。 Awaiter概念包括以下约束:await_readyawait_suspendawait_resume。可等待的概念有以下限制:(1)co_await特化/重载和(2)await_transform不重载。[ref]
任务类型如下所示:
class task
  {
  public:

    using promise_type = <unspecified>;
    using value_type = T;

    task() noexcept;

    task(task&& other) noexcept;
    task& operator=(task&& other);

    task(const task& other) = delete;
    task& operator=(const task& other) = delete;

    bool is_ready() const noexcept;

    Awaiter<T&> operator co_await() const & noexcept;
    Awaiter<T&&> operator co_await() const && noexcept;


    Awaitable<void> when_ready() const noexcept;
  };
您可以选择使用这些概念(最好是我的方法),或者如果您还不熟悉这些概念的存在,那么您可能需要自己实现相关的约束才能实现。
使用任务就像[ref]一样简单:
task<> tcp_echo_server() {
  char data[1024];
  for (;;) {
    size_t n = co_await socket.async_read_some(buffer(data));
    co_await async_write(socket, buffer(data, n));
  }
}

关于c++ - C++:如何正确使用#include <协程>中可用的generator <>,task <>和lazy <>类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64542433/

相关文章:

c++ - 如何在 GCC 中使用 c++20 模块?

c++ - LNK2019 : "Unresolved external symbol" with rapidjson

c++ - table = new HashEntry*[TABLE_SIZE]

c++ - 如何修复 C++ 项目中的内存泄漏?

c++ - 使用 Boost.Asio 的广播问题

c++ - 如何为非类型模板arg定义等效规则

c++ - 三个简单的makefile问题

javascript - 像curl一样发送post数据

c++ - Visual Studio 2013 Boost-log v1_61_0 链接错误

c++ - 如何将模板化固定字符串传递给另一个类的构造函数的重载