#async-executor #async-task #executor #async #future #events

no-std extern_executor

将 futures 的轮询委托给外部事件循环的异步执行器

2 个版本

0.1.2 2020 年 4 月 19 日
0.1.0 2020 年 4 月 17 日

#1873 in 异步

MIT 许可证

26KB
416

异步 Rust 的外部执行器

本项目旨在提供简单的执行器,帮助将异步 Rust 代码运行到外部事件循环中。例如,当您开发包含 Rust 中的异步代码的动态链接库,并希望在不同的执行环境中运行它时,这可能很有用。

使用方法

Rust 端,您应该将 extern_executor 添加为依赖项到您的 cdylib 库,并使用 spawn() 函数运行 futures,如下所示

use extern_executor::spawn;

spawn(async {
  // your awaits
});

C 端,您应该使用您首选的事件循环 API 实现执行器的驱动程序。例如,当使用 libuv 时,它可能看起来像这样

#include <uv.h>
#include <rust_async_executor.h>

static void task_wake(RustAsyncExecutorExternTask data) {
    uv_async_t* handle = data;
    // wakeup uv's async task
    uv_async_send(handle);
}

static void task_poll(uv_async_t* handle) {
    // poll internal task until task complete
    if (!rust_async_executor_poll(handle->data)) {
        // drop internal task when task complete
        rust_async_executor_drop(handle->data);
        // drop uv's async task handle
        uv_close((uv_handle_t*)handle, NULL);
    }
}

static RustAsyncExecutorExternTask
task_new(RustAsyncExecutorUserData data) {
    uv_loop_t* loop = data;
    // crate and initialize uv's async task handle
    uv_async_t* handle = malloc(sizeof(uv_async_t));
    uv_async_init(loop, handle, task_poll);
    return handle;
}

static void task_run(RustAsyncExecutorExternTask task,
                     RustAsyncExecutorInternTask data) {
    uv_async_t* handle = task;
    // store internal task handle to be able to poll it later
    handle->data = data;
    uv_async_send(handle); // do initial polling (important)
}

void uv_rust_async_executor_init(uv_loop_t *loop) {
    // send out executor API to Rust side
    rust_async_executor_init(task_new, task_run, task_wake, loop);
}

现在您可以在 libuv 的事件循环中运行您的异步代码,如下所示

int main(void) {
    uv_loop_t loop;

    uv_loop_init(&loop);
    uv_rust_async_executor_init(&loop);

    my_async_function(my_async_callback);

    uv_run(&loop, UV_RUN_DEFAULT);
    uv_loop_close(&loop);

    return 0;
}

使用 cbindgen 生成的 C 头文件 rust_async_executor.h。有两种方法可以获取它

  • 从本仓库的 include 目录复制
  • 通过您自己的 cbindgen 功能生成

在第二种情况下,生成的头文件将位于 target/$PROFILE/include 目录。

内置事件循环驱动程序

为了简化某些广泛使用的事件循环的设置,引入了内置的驱动程序。要使用驱动程序,您应该启用相应的功能。目前支持的以下驱动程序

  • uv 内置的 libuv 事件循环集成(见 example_uv
  • dart 内置的 dart-lang 事件循环集成(见 example_dart

链接问题

Rust 目前存在与从库依赖项重新导出符号相关的问题 (#2771)。

作为临时解决方案,您可以设置构建配置文件如下

[profile.release]
lto = true
incremental = false

与 Tokio 兼容性

此执行器与 tokio 的 futures 不兼容,因为 tokio 仍然有一个与反应器混合的非平凡执行器。

依赖项

~0–1MB