这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

Rust 陷阱

Drop 不一定会执行

一个结构的 destructor (即 Drop)不一定保证会执行,这也是 std 移除 thread::scoped 这个 API 的原因,下面这几篇文章都对其进行了详细分析。

  • Async Rust: history strikes back.

    • Reference counting is not the end of the world. As a matter of fact, in an earlier essay I have argued that they are the price we pay to live in a civilized asynchronous world.
    • Glommio 中 ScopedTask 的效果

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      async fn some_async_function() {
        let shared = Rc::new(Cell::new(0));
        let s = shared.clone();
      
        let x = Task::local(async move {
            do_async_work(s).await; // used a Clone of shared state
        }); // <== task starts executing here
      
        do_more_work(shared); // <== may be still background executing here
      
        x.await; // <== but is surely done here.
      }
  • C++ vs Rust: an async Thread-per-Core story

    • The borrow checker works well for things that happen at predictable times. But once you start implementing things like an asynchronous call, or a queue of requests that will be consumed by io_uring at a later time and are stored in a on-heap array, things get more complex. Take the following code as a toy example:

使用异步特性强制分配内存

目前,async fn 无法在 Rust 稳定版本的 traits 中使用。 自 2022 年 11 月 17 日起,async-fn-in-trait 的 MVP 可在编译器工具链的夜间版本中使用,详情请参阅此处

与此同时,在稳定版工具链中可以使用 async-trait 来解决这一问题。

请注意,使用这些 trait 方法会导致每次函数调用都要进行堆分配。 对于绝大多数应用程序来说,这并不是一个 很大的代价,但在决定是否在低级函数的公共 API 中使用此功能时,应考虑到该函数预计每秒会被调用数百万次。

2 - PyO3

PyO3 是使用 Rust 开发 Python 插件的库。 curl-py 是我写的一个示例项目,通过 pyo3 将 libcurl 暴露给 Python 使用。

打包分发时,会用到 PyO3/maturin-action,它会自动使用 manylinux 镜像来打包,尽可能多的保证最后的二进制文件可以在多个 linux 平台上使用。

pypa/manylinux

Python wheels that work on any linux (almost) 这是 Python 官方提供的一组 Docker 静态,用来打包、分发含有二进制的 Python 包,有多个版本:

  • PEP 513 (manylinux1)
  • PEP 571 (manylinux2010)
  • PEP 599 (manylinux2014)
  • PEP 600 (manylinux_x_y)
  • PEP 656 (musllinux_x_y)

现在主要用的就是最后两个,最后的 xy 表示的是 glibc 的版本,比如:manylinux_2_28。 不同镜像支持的系统,可以参见:https://github.com/pypa/manylinux?tab=readme-ov-file#docker-images

manylinux_2_28 (AlmaLinux 8 based)

Toolchain: GCC 13

  • x86_64 image: quay.io/pypa/manylinux_2_28_x86_64
  • aarch64 image: quay.io/pypa/manylinux_2_28_aarch64
  • ppc64le image: quay.io/pypa/manylinux_2_28_ppc64le
  • s390x image: quay.io/pypa/manylinux_2_28_s390x

兼容的系统

  • Debian 10+
  • Ubuntu 18.10+
  • Fedora 29+
  • CentOS/RHEL 8+

PyO3 使用注意事项

  • pymodule 标注的函数名要与 cargo 中的 name 一致,如果函数名会与现有模块名冲突,可以用下面方式解决:

    1
    2
    3
    4
    5
    
    #[pymodule(name = "vsag")]
    fn vsag_py(m: &Bound<'_, PyModule>) -> PyResult<()> {
      m.add_class::<Index>()?;
      Ok(())
    }

Maturin-action

  • 使用