#coroutine #fiber #hook #async-io #file-io #thread-pool #stackfull

open-coroutine

The open-coroutine is a simple, efficient and generic stackfull-coroutine library

33 releases

new 0.6.15 Jan 11, 2025
0.6.14 Jan 1, 2025
0.6.10 Oct 22, 2024
0.5.0 Jan 21, 2024
0.0.7 Nov 17, 2022

#101 in Asynchronous

Download history 2/week @ 2024-09-18 10/week @ 2024-09-25 4/week @ 2024-10-02 1003/week @ 2024-10-16 572/week @ 2024-10-23 2/week @ 2024-10-30 2/week @ 2024-11-06 40/week @ 2024-11-27 313/week @ 2024-12-04 213/week @ 2024-12-11 12/week @ 2024-12-18 2/week @ 2024-12-25 611/week @ 2025-01-01

921 downloads per month

Apache-2.0

470KB
11K SLoC

open-coroutine

crates.io docs.rs LICENSE Build Status Codecov Average time to resolve an issue Percentage of issues still open

The open-coroutine is a simple, efficient and generic stackfull-coroutine library, you can use this as a performance replacement for IO thread pools, see why better.

English | 中文

🚀 Features

  • Preemptive(not supported in windows): even if the coroutine enters a dead loop, it can still be seized, see example;
  • Hook: you are free to use most of the slow syscall in coroutine, see supported syscall on unix/windows;
  • Scalable: the size of the coroutine stack supports unlimited expansion without the cost of copying stack, and immediately shrinks to the original size after use, see example;
  • io_uring(only in linux): supports and is compatible with io_uring in terms of local file IO and network IO. If it's not supported on your system, it will fall back to non-blocking IO;
  • Priority: support custom task priority, note that coroutine priority is not open to users;
  • Work Steal: internally using a lock free work steal queue;
  • Compatibility: the implementation of open-coroutine is no async, but it is compatible with async, which means you can use this crate in tokio/async-std/smol/...;
  • Platforms: running on Linux, macOS and Windows;

🕊 Roadmap

  • add docs;
  • add performance benchmark;
  • cancel coroutine/task;
  • add metrics;
  • add synchronization toolkit;
  • support and compatibility for AF_XDP socket;

🏠 Architecture

graph TD
    subgraph ApplicationFramework
        Tower
        Actix-Web
        Rocket
        warp
        axum
    end
    subgraph MessageQueue
        RocketMQ
        Pulsar
    end
    subgraph RemoteProcedureCall
        Dubbo
        Tonic
        gRPC-rs
        Volo
    end
    subgraph Database
        MySQL
        Oracle
    end
    subgraph NetworkFramework
        Tokio
        monoio
        async-std
        smol
    end
    subgraph open-coroutine-architecture
        subgraph core
            Preemptive
            ScalableStack
            WorkSteal
            Priority
        end
        subgraph hook
            HookSyscall
        end
        subgraph macros
            open-coroutine::main
        end
        subgraph open-coroutine
        end
        hook -->|depends on| core
        open-coroutine -->|link| hook
        open-coroutine -->|depends on| macros
    end
    subgraph OperationSystem
        Linux
        macOS
        Windows
    end
    ApplicationFramework -->|maybe depends on| RemoteProcedureCall
    ApplicationFramework -->|maybe depends on| MessageQueue
    ApplicationFramework -->|maybe depends on| Database
    MessageQueue -->|depends on| NetworkFramework
    RemoteProcedureCall -->|depends on| NetworkFramework
    NetworkFramework -->|runs on| OperationSystem
    NetworkFramework -->|can depends on| open-coroutine-architecture
    Database -->|runs on| OperationSystem
    open-coroutine-architecture -->|runs on| OperationSystem

📖 Quick Start

step1: add dependency to your Cargo.toml

[dependencies]
# check https://crates.io/crates/open-coroutine
open-coroutine = "x.y.z"

step2: add open_coroutine::main macro

#[open_coroutine::main]
fn main() {
    //......
}

step3: create a task

#[open_coroutine::main]
fn main() {
    _ = open_coroutine::task!(|param| {
        assert_eq!(param, "param");
    }, "param");
}

🪶 Advanced Usage

create a task with priority

#[open_coroutine::main]
fn main() {
    _ = open_coroutine::task!(|param| {
        assert_eq!(param, "param");
    }, "param", 1/*the smaller the value, the higher the priority*/);
}

wait until the task is completed or timed out

#[open_coroutine::main]
fn main() {
    let task = open_coroutine::task!(|param| {
        assert_eq!(param, "param");
    }, "param", 1);
    task.timeout_join(std::time::Duration::from_secs(1)).expect("timeout");
}

scalable stack

#[open_coroutine::main]
fn main() {
    _ = open_coroutine::task!(|_| {
        fn recurse(i: u32, p: &mut [u8; 10240]) {
            open_coroutine::maybe_grow!(|| {
                // Ensure the stack allocation isn't optimized away.
                unsafe { _ = std::ptr::read_volatile(&p) };
                if i > 0 {
                    recurse(i - 1, &mut [0; 10240]);
                }
            })
            .expect("allocate stack failed")
        }
        println!("[task] launched");
        // Use ~500KB of stack.
        recurse(50, &mut [0; 10240]);
    }, ());
}

⚓ Learn More

我有故事,你有酒吗?

👍 Credits

This crate was inspired by the following projects:

Thanks to those who have provided assistance:

Amanieu bjorn3 workingjubilee Noratrieb

Dependencies

~5–33MB
~480K SLoC