6 releases

new 0.1.37 Nov 25, 2024
0.1.36 Nov 19, 2024
0.1.0 Oct 26, 2024

#464 in Asynchronous

Download history 103/week @ 2024-10-21 89/week @ 2024-10-28 181/week @ 2024-11-04 436/week @ 2024-11-11 232/week @ 2024-11-18

1,008 downloads per month

Apache-2.0

72KB
1.5K SLoC

Hooch

Overview

Hooch is a custom async runtime written in Rust. The runtime serves as a lightweight, experimental alternative to existing asynchronous frameworks, allowing for a deeper understanding of async runtime internals.

Features

  • Custom Executor and Reactor: Implements basic building blocks for async task scheduling and polling.
  • Minimal Dependencies: Lightweight and tailored specifically to async task handling.

Usage

Below are examples demonstrating basic use cases for Hooch's async runtime.

Example 1: Spawning and Awaiting a Task with JoinHandle

In this example, we create a task within the runtime and use a JoinHandle to await its completion and retrieve the result. The JoinHandle allows you to asynchronously wait for the result of a spawned task, making it useful for concurrent operations.

use hooch::runtime::RuntimeBuilder;

fn main() {
    let runtime_handle = RuntimeBuilder::default().build();

    runtime_handle.run_blocking(async {
        // Creating a runtime instance for this thread
        RuntimeBuilder::default().build();
        let handle = hooch::spawner::Spawner::spawn(async { 3 });
        let value = handle.await.unwrap();

        assert_eq!(value, 3);
        println!("Received value from task: {}", value);
    });
}

Example 2: Using Bounded Channels for Communication between Threads

This example demonstrates using a bounded channel to send data between threads. Here, we create a sender thread that transmits a value through a bounded channel, and a receiver in the async runtime awaits and receives it.

use std::sync::{Arc, Mutex};
use hooch::{runtime::RuntimeBuilder, sync::mpsc::bounded_channel};

fn main() {
    let (tx, rx) = bounded_channel::<i32>(1000);
    let runtime_handle = RuntimeBuilder::default().build();

    // Spawning a thread that sends a value through the channel
    std::thread::Builder::new()
        .name("sender".into())
        .spawn(move || {
            std::thread::sleep(std::time::Duration::from_millis(100));
            let _ = tx.send(1);
        })
        .unwrap();

    // Receiving the value in the async runtime
    let result = Arc::new(Mutex::new(0));
    let result_clone = Arc::clone(&result);
    runtime_handle.run_blocking(async move {
        let rx_res = rx.recv().await.unwrap();
        *result_clone.lock().unwrap() = rx_res;
    });

    assert_eq!(*result.lock().unwrap(), 1);
    println!("Received value from channel: {}", *result.lock().unwrap());
}

Time

Sleep functionality is included with hooch.

use std::time::Duration;
use hooch::{runtime::RuntimeBuilder, time::sleep};

fn main() {
    let runtime_handle = RuntimeBuilder::default().build();
    runtime_handle.run_blocking(async move {
        sleep(Duration::from_millis(sleep_milliseconds)).await;
    });
}

Hooch macros

#[hooch_main] is a proc_macro_attribute that conveniently wraps your main function in the runtime. The only argument is workers, which defines the number of workers used. If the argument is not present, the default number of workers from the RuntimeBuilder will be used.

Examples

Using RuntimeBuilder default number of workers

use hooch::hooch_main;

#[hooch_main]
async fn main() {
    println!("Default number of workers in Runtime builder");
}

Using 4 workers

use hooch::hooch_main;

#[hooch_main(workers = 4)]
async fn main() {
    println!("Use 4 workers in the runtime");
}

Dependencies

~3–10MB
~116K SLoC