最近在项目中尝试了rust下的协程库May。如果你对写async\await感到厌倦,可以试试May,换换脑子。

介绍

May是一个用pure rust写的基于栈的协程库。官方的介绍如下:

May is a high-performant library for programming stackful coroutines with which you can easily develop and maintain massive concurrent programs. It can be thought as the Rust version of the popular Goroutine.

常见的协程库,在python下有gevent, c\c++libuv。在rust下也有其它基于ffi封装的libuv等库。

Future简单对比

MayrustFuture有哪些相同和不同的地方?

相同的地方:

  • 都是基于generator实现的,也就是说都是stackful
  • 捕获的变量都需要move
  • 都需要runtime去执行

不同的地方:

  • Future需要pin reference, May不需要(可能也需要?)

  • Future使用async\await关键字,May不需要

示例

下面的示例简单展示了taskspawncancel

#[macro_use]
extern crate may;

use may::coroutine as co;
use std::time::{Duration, Instant};
fn main() {
    let t = go!(|| main_task());
    t.join();
}

fn main_task() {
    let mut tasks = vec![];
    for i in 0..10 {
        let task = go!(move || { child_task(i) });
        tasks.push(task);
    }
    co::sleep(Duration::from_secs(3));
    for (i, t) in (&tasks[0..5]).iter().enumerate() {
        unsafe {
            t.coroutine().cancel();
            println!("child {}: cancelled", i);
        }
    }
    for t in tasks {
        t.join();
    }
    println!("all done!");
}

fn child_task(index: usize) {
    let now = Instant::now();
    loop {
        if now.elapsed() > Duration::from_secs(20) {
            println!("child {}: done", index);
            break;
        }
        println!("child {}: running", index);
        co::sleep(Duration::from_millis(500));
    }
}

Cancel 的问题

使用cancel后发现程序在release模式下莫名的崩溃。 调试及查看源代码,发现是由于Maycancel机制使用rustpanic机制。所以无法在编译时优化使用自定义的panic处理机制。

[profile.release]
panic = "abort"

如果使用这个配置,cancel()时应用程序会崩溃退出。

进一步阅读may的代码发现,may不会主动panicpanic是由于其它代码panic被它捕捉到了。可能是哪里unwrap之类的调用抛出的。