mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-25 00:00:18 +02:00
Introduce the Tokio runtime: Reactor + Threadpool (#141)
This patch is an intial implementation of the Tokio runtime. The Tokio runtime provides an out of the box configuration for running I/O heavy asynchronous applications. As of now, the Tokio runtime is a combination of a work-stealing thread pool as well as a background reactor to drive I/O resources. This patch also includes tokio-executor, a hopefully short lived crate that is based on the futures 0.2 executor RFC. * Implement `Park` for `Reactor` This enables the reactor to be used as the thread parker for executors. This also adds an `Error` component to `Park`. With this change, a `Reactor` and a `CurrentThread` can be combined to achieve the capabilities of tokio-core.
This commit is contained in:
+203
-4
@@ -1,8 +1,207 @@
|
||||
//! Task execution utilities.
|
||||
//!
|
||||
//! This module only contains `current_thread`, an executor for multiplexing
|
||||
//! many tasks on a single thread.
|
||||
//! In the Tokio execution model, futures are lazy. When a future is created, no
|
||||
//! work is performed. In order for the work defined by the future to happen,
|
||||
//! the future must be submitted to an executor. A future that is submitted to
|
||||
//! an executor is called a "task".
|
||||
//!
|
||||
//! The executor executor is responsible for ensuring that [`Future::poll`] is
|
||||
//! called whenever the task is [notified]. Notification happens when the
|
||||
//! internal state of a task transitions from "not ready" to ready. For
|
||||
//! example, a socket might have received data and a call to `read` will now be
|
||||
//! able to succeed.
|
||||
//!
|
||||
//! The specific strategy used to manage the tasks is left up to the
|
||||
//! executor. There are two main flavors of executors: single-threaded and
|
||||
//! multithreaded. This module provides both.
|
||||
//!
|
||||
//! * **[`current_thread`]**: A single-threaded executor that support spawning
|
||||
//! tasks that are not `Send`. It guarantees that tasks will be executed on
|
||||
//! the same thread from which they are spawned.
|
||||
//!
|
||||
//! * **[`thread_pool`]**: A multi-threaded executor that maintains a pool of
|
||||
//! threads. Tasks are spawned to one of the threads in the pool and executed.
|
||||
//! The pool employes a [work-stealing] strategy for optimizing how tasks get
|
||||
//! spread across the available threads.
|
||||
//!
|
||||
//! # `Executor` trait.
|
||||
//!
|
||||
//! This module provides the [`Executor`] trait (re-exported from
|
||||
//! [`tokio-executor`]), which describes the API that all executors must
|
||||
//! implement.
|
||||
//!
|
||||
//! A free [`spawn`] function is provided that allows spawning futures onto the
|
||||
//! default executor (tracked via a thread-local variable) without referencing a
|
||||
//! handle. It is expected that all executors will set a value for the default
|
||||
//! executor. This value will often be set to the executor itself, but it is
|
||||
//! possible that the default executor might be set to a different executor.
|
||||
//!
|
||||
//! For example, the [`current_thread`] executor might set the default executor
|
||||
//! to a thread pool instead of itself, allowing futures to spawn new tasks onto
|
||||
//! the thread pool when those tasks are `Send`.
|
||||
//!
|
||||
//! [`Future::poll`]: https://docs.rs/futures/0.1/futures/future/trait.Future.html#tymethod.poll
|
||||
//! [notified]: https://docs.rs/futures/0.1/futures/executor/trait.Notify.html#tymethod.notify
|
||||
//! [`current_thread`]: current_thread/index.html
|
||||
//! [`thread_pool`]: thread_pool/index.html
|
||||
//! [work-stealing]: https://en.wikipedia.org/wiki/Work_stealing
|
||||
//! [`tokio-executor`]: #
|
||||
//! [`Executor`]: #
|
||||
//! [`spawn`]: #
|
||||
|
||||
|
||||
pub mod current_thread;
|
||||
mod scheduler;
|
||||
mod sleep;
|
||||
|
||||
pub mod thread_pool {
|
||||
//! Maintains a pool of threads across which the set of spawned tasks are
|
||||
//! executed.
|
||||
//!
|
||||
//! [`ThreadPool`] is an executor that uses a thread pool for executing
|
||||
//! tasks concurrently across multiple cores. It uses a thread pool that is
|
||||
//! optimized for use cases that involve multiplexing large number of
|
||||
//! independent tasks that perform short(ish) amounts of computation and are
|
||||
//! mainly waiting on I/O, i.e. the Tokio use case.
|
||||
//!
|
||||
//! Usually, users of [`ThreadPool`] will not create pool instances.
|
||||
//! Instead, they will create a [`Runtime`] instance, which comes with a
|
||||
//! pre-configured thread pool.
|
||||
//!
|
||||
//! At the core, [`ThreadPool`] uses a work-stealing based scheduling
|
||||
//! strategy. When spawning a task while *external* to the thread pool
|
||||
//! (i.e., from a thread that is not part of the thread pool), the task is
|
||||
//! randomly assigned to a worker thread. When spawning a task while
|
||||
//! *internal* to the thread pool, the task is assigned to the current
|
||||
//! worker.
|
||||
//!
|
||||
//! Each worker maintains its own queue and first focuses on processing all
|
||||
//! tasks in its queue. When the worker's queue is empty, the worker will
|
||||
//! attempt to *steal* tasks from other worker queues. This strategy helps
|
||||
//! ensure that work is evenly distributed across threads while minimizing
|
||||
//! synchronization between worker threads.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! Thread pool instances are created using [`ThreadPool::new`] or
|
||||
//! [`Builder::new`]. The first option returns a thread pool with default
|
||||
//! configuration values. The second option allows configuring the thread
|
||||
//! pool before instantiating it.
|
||||
//!
|
||||
//! Once an instance is obtained, futures may be spawned onto it using the
|
||||
//! [`spawn`] function.
|
||||
//!
|
||||
//! A handle to the thread pool is obtained using [`ThreadPool::sender`].
|
||||
//! This handle is **only** able to spawn futures onto the thread pool. It
|
||||
//! is unable to affect the lifecycle of the thread pool in any way. This
|
||||
//! handle can be passed into functions or stored in structs as a way to
|
||||
//! grant the capability of spawning futures.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate tokio;
|
||||
//! # extern crate futures;
|
||||
//! # use tokio::executor::thread_pool::ThreadPool;
|
||||
//! use futures::future::{Future, lazy};
|
||||
//!
|
||||
//! # pub fn main() {
|
||||
//! // Create a thread pool with default configuration values
|
||||
//! let thread_pool = ThreadPool::new();
|
||||
//!
|
||||
//! thread_pool.spawn(lazy(|| {
|
||||
//! println!("called from a worker thread");
|
||||
//! Ok(())
|
||||
//! }));
|
||||
//!
|
||||
//! // Gracefully shutdown the threadpool
|
||||
//! thread_pool.shutdown().wait().unwrap();
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! [`ThreadPool`]: struct.ThreadPool.html
|
||||
//! [`ThreadPool::new`]: struct.ThreadPool.html#method.new
|
||||
//! [`ThreadPool::sender`]: struct.ThreadPool.html#method.sender
|
||||
//! [`spawn`]: struct.ThreadPool.html#method.spawn
|
||||
//! [`Builder::new`]: struct.Builder.html#method.new
|
||||
//! [`Runtime`]: ../../runtime/struct.Runtime.html
|
||||
|
||||
pub use tokio_threadpool::{
|
||||
Builder,
|
||||
Sender,
|
||||
Shutdown,
|
||||
ThreadPool,
|
||||
};
|
||||
}
|
||||
|
||||
pub use tokio_executor::{Executor, DefaultExecutor, SpawnError};
|
||||
|
||||
use futures::{Future, Poll, Async};
|
||||
|
||||
/// Future, returned by `spawn`, that completes once the future is spawned.
|
||||
///
|
||||
/// See [`spawn`] for more details.
|
||||
///
|
||||
/// [`spawn`]: fn.spawn.html
|
||||
#[derive(Debug)]
|
||||
#[must_use = "Spawn does nothing unless polled"]
|
||||
pub struct Spawn<F>(Option<F>);
|
||||
|
||||
/// Spawns a future on the default executor.
|
||||
///
|
||||
/// In order for a future to do work, it must be spawned on an executor. The
|
||||
/// `spawn` function is the easiest way to do this. It spawns a future on the
|
||||
/// [default executor] for the current execution context (tracked using a
|
||||
/// thread-local variable).
|
||||
///
|
||||
/// The default executor is **usually** a thread pool.
|
||||
///
|
||||
/// Note that the function doesn't immediately spawn the future. Instead, it
|
||||
/// returns `Spawn`, which itself is a future that completes once the spawn has
|
||||
/// succeeded.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// In this example, a server is started and `spawn` is used to start a new task
|
||||
/// that processes each received connection.
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate tokio;
|
||||
/// # extern crate futures;
|
||||
/// # use futures::{Future, Stream};
|
||||
/// use tokio::net::TcpListener;
|
||||
///
|
||||
/// # fn process<T>(_: T) -> Box<Future<Item = (), Error = ()> + Send> {
|
||||
/// # unimplemented!();
|
||||
/// # }
|
||||
/// # fn dox() {
|
||||
/// # let addr = "127.0.0.1:8080".parse().unwrap();
|
||||
/// let listener = TcpListener::bind(&addr).unwrap();
|
||||
///
|
||||
/// let server = listener.incoming()
|
||||
/// .map_err(|e| println!("error = {:?}", e))
|
||||
/// .for_each(|socket| {
|
||||
/// tokio::spawn(process(socket))
|
||||
/// });
|
||||
///
|
||||
/// tokio::run(server);
|
||||
/// # }
|
||||
/// # pub fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// [default executor]: struct.DefaultExecutor.html
|
||||
pub fn spawn<F>(f: F) -> Spawn<F>
|
||||
where F: Future<Item = (), Error = ()> + 'static + Send
|
||||
{
|
||||
Spawn(Some(f))
|
||||
}
|
||||
|
||||
impl<F> Future for Spawn<F>
|
||||
where F: Future<Item = (), Error = ()> + Send + 'static
|
||||
{
|
||||
type Item = ();
|
||||
type Error = ();
|
||||
|
||||
fn poll(&mut self) -> Poll<(), ()> {
|
||||
::tokio_executor::spawn(self.0.take().unwrap());
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user