mirror of https://github.com/stjepang/smol
More comments
This commit is contained in:
parent
72b5b2deac
commit
78a867e455
|
@ -16,12 +16,12 @@ A small and fast async runtime for Rust.
|
|||
|
||||
This runtime extends [the standard library][std] and
|
||||
[futures] with async combinators.
|
||||
It has a small API and is only 1500 lines of well-documented code.
|
||||
It has a very small API and consists of only 1500 lines of well-documented code.
|
||||
|
||||
[std]: https://docs.rs/std
|
||||
[futures]: https://docs.rs/futures
|
||||
|
||||
Reading [docs] and [examples] is a good place to start learning async Rust.
|
||||
Reading the [docs] and [examples] is a good place to start learning async Rust.
|
||||
|
||||
[docs]: https://docs.rs/smol
|
||||
[examples]: ./examples
|
||||
|
@ -79,7 +79,7 @@ My personal crate recommendation list:
|
|||
* HTTP clients: [surf], [isahc], [reqwest]
|
||||
* HTTP servers: [async-h1], [hyper]
|
||||
* WebSockets: [tungstenite]
|
||||
* TLS authentication: [async-native-tls] and [native-tls]
|
||||
* TLS authentication: [async-native-tls]
|
||||
* Signals: [ctrlc], [signal-hook]
|
||||
|
||||
[piper]: https://docs.rs/piper
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// TODO: document
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use smol::Timer;
|
||||
|
||||
async fn sleep(dur: Duration) {
|
||||
Timer::after(dur).await;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
smol::run(async {
|
||||
let start = Instant::now();
|
||||
println!("Sleeping...");
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
println!("Woke up after {:?}", start.elapsed());
|
||||
})
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// TODO: document
|
||||
use std::io;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use futures::io::BufReader;
|
||||
use futures::prelude::*;
|
||||
use smol::Timer;
|
||||
|
||||
async fn timeout<T>(dur: Duration, f: impl Future<Output = io::Result<T>>) -> io::Result<T> {
|
||||
futures::select! {
|
||||
out = f.fuse() => out,
|
||||
_ = Timer::after(dur).fuse() => {
|
||||
Err(io::Error::from(io::ErrorKind::TimedOut))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
smol::run(async {
|
||||
let mut line = String::new();
|
||||
let mut stdin = BufReader::new(smol::reader(std::io::stdin()));
|
||||
|
||||
timeout(Duration::from_secs(5), stdin.read_line(&mut line)).await?;
|
||||
println!("Line: {}", line);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
|
@ -36,8 +36,10 @@ pub(crate) struct BlockingExecutor {
|
|||
struct State {
|
||||
/// Number of sleeping threads in the pool.
|
||||
idle_count: usize,
|
||||
|
||||
/// Total number of thread in the pool.
|
||||
thread_count: usize,
|
||||
|
||||
/// Runnable blocking tasks.
|
||||
queue: VecDeque<Runnable>,
|
||||
}
|
||||
|
|
65
src/run.rs
65
src/run.rs
|
@ -17,16 +17,75 @@ use crate::work_stealing::WorkStealingExecutor;
|
|||
/// calling [`run()`] in order for futures waiting on I/O and timers to get notified.
|
||||
///
|
||||
/// # Examples
|
||||
/// TODO a thread-pool example with num_cpus::get().max(1)
|
||||
/// TODO a stoppable thread-pool with channels
|
||||
///
|
||||
/// Single-threaded executor:
|
||||
///
|
||||
/// ```
|
||||
/// smol::run(async {
|
||||
/// println!("Hello from the smol executor!");
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Multi-threaded executor:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use futures::future;
|
||||
/// use smol::Task;
|
||||
/// use std::thread;
|
||||
///
|
||||
/// for _ in 0..num_cpus::get().max(1) {
|
||||
/// // Same number of threads as there are CPU cores.
|
||||
/// let num_threads = num_cpus::get().max(1);
|
||||
///
|
||||
/// // Create an executor thread pool.
|
||||
/// for _ in 0..num_threads {
|
||||
/// // A pending future is one that simply yields forever.
|
||||
/// thread::spawn(|| smol::run(future::pending::<()>()));
|
||||
/// }
|
||||
///
|
||||
/// // No need to `run()`, now we can just block on the main future.
|
||||
/// smol::block_on(async {
|
||||
/// Task::spawn(async {
|
||||
/// println!("Hello from an executor thread!");
|
||||
/// })
|
||||
/// .await;
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Stoppable multi-threaded executor:
|
||||
///
|
||||
/// ```
|
||||
/// use smol::Task;
|
||||
/// use std::thread;
|
||||
///
|
||||
/// // Same number of threads as there are CPU cores.
|
||||
/// let num_threads = num_cpus::get().max(1);
|
||||
///
|
||||
/// // A channel that sends the shutdown signal.
|
||||
/// let (s, r) = piper::chan::<()>(0);
|
||||
/// let mut threads = Vec::new();
|
||||
///
|
||||
/// // Create an executor thread pool.
|
||||
/// for _ in 0..num_cpus::get().max(1) {
|
||||
/// // Spawn an executor thread that waits for the shutdown signal.
|
||||
/// let r = r.clone();
|
||||
/// threads.push(thread::spawn(move || smol::run(r.recv())));
|
||||
/// }
|
||||
///
|
||||
/// // No need to `run()`, now we can just block on the main future.
|
||||
/// smol::block_on(async {
|
||||
/// Task::spawn(async {
|
||||
/// println!("Hello from an executor thread!");
|
||||
/// })
|
||||
/// .await;
|
||||
/// });
|
||||
///
|
||||
/// // Send a shutdown signal.
|
||||
/// drop(s);
|
||||
///
|
||||
/// // Wait for threads to finish.
|
||||
/// for t in threads {
|
||||
/// t.join().unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
pub fn run<T>(future: impl Future<Output = T>) -> T {
|
||||
// Create a thread-local executor and a worker in the work-stealing executor.
|
||||
|
|
|
@ -44,7 +44,7 @@ impl ThreadLocalExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Enters the context of this executor.
|
||||
pub fn enter<T>(&self, f: impl FnOnce() -> T) -> T {
|
||||
if EXECUTOR.is_set() {
|
||||
panic!("cannot run an executor inside another executor");
|
||||
|
@ -52,7 +52,7 @@ impl ThreadLocalExecutor {
|
|||
EXECUTOR.set(self, f)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Returns the event indicating there is a scheduled task.
|
||||
pub fn event(&self) -> &IoEvent {
|
||||
&self.event
|
||||
}
|
||||
|
|
53
src/timer.rs
53
src/timer.rs
|
@ -8,6 +8,8 @@ use crate::reactor::Reactor;
|
|||
|
||||
/// Fires at the chosen point in time.
|
||||
///
|
||||
/// Timers are futures that output the [`Instant`] at which they fired.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Sleep for 1 second:
|
||||
|
@ -24,6 +26,33 @@ use crate::reactor::Reactor;
|
|||
/// sleep(Duration::from_secs(1)).await;
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// Set a timeout on an I/O operation:
|
||||
///
|
||||
/// ```
|
||||
/// use futures::prelude::*;
|
||||
/// use futures::io::{self, BufReader};
|
||||
/// use smol::Timer;
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// async fn timeout<T>(
|
||||
/// dur: Duration,
|
||||
/// f: impl Future<Output = io::Result<T>>,
|
||||
/// ) -> io::Result<T> {
|
||||
/// futures::select! {
|
||||
/// t = f.fuse() => t,
|
||||
/// _ = Timer::after(dur).fuse() => Err(io::Error::from(io::ErrorKind::TimedOut)),
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # smol::run(async {
|
||||
/// // Create a buffered stdin reader.
|
||||
/// let mut stdin = BufReader::new(smol::reader(std::io::stdin()));
|
||||
///
|
||||
/// // Read a line within 5 seconds.
|
||||
/// let mut line = String::new();
|
||||
/// timeout(Duration::from_secs(5), stdin.read_line(&mut line)).await?;
|
||||
/// # io::Result::Ok(()) });
|
||||
#[derive(Debug)]
|
||||
pub struct Timer {
|
||||
/// A unique ID for this timer.
|
||||
|
@ -38,14 +67,34 @@ pub struct Timer {
|
|||
impl Timer {
|
||||
/// Fires after the specified duration of time.
|
||||
///
|
||||
/// TODO
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use smol::Timer;
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// # smol::run(async {
|
||||
/// Timer::after(Duration::from_secs(1)).await;
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn after(dur: Duration) -> Timer {
|
||||
Timer::at(Instant::now() + dur)
|
||||
}
|
||||
|
||||
/// Fires at the specified instant in time.
|
||||
///
|
||||
/// TODO
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use smol::Timer;
|
||||
/// use std::time::{duration, Instant};
|
||||
///
|
||||
/// # smol::run(async {
|
||||
/// let now = Instant::now();
|
||||
/// let when = now + Duration::from_secs(1);
|
||||
/// Timer::after(when).await;
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn at(when: Instant) -> Timer {
|
||||
let id = None;
|
||||
Timer { id, when }
|
||||
|
|
|
@ -68,7 +68,7 @@ impl WorkStealingExecutor {
|
|||
&EXECUTOR
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// Returns the event indicating there is a scheduled task.
|
||||
pub fn event(&self) -> &IoEvent {
|
||||
&self.event
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ pub(crate) struct Worker<'a> {
|
|||
}
|
||||
|
||||
impl Worker<'_> {
|
||||
/// TODO
|
||||
/// Enters the context of this executor.
|
||||
pub fn enter<T>(&self, f: impl FnOnce() -> T) -> T {
|
||||
if WORKER.is_set() {
|
||||
panic!("cannot run an executor inside another executor");
|
||||
|
|
Loading…
Reference in New Issue