Crate tokio_timer [−] [src]
Timer facilities for Tokio
The default timer implementation is a hashed timing wheel. This structure
provides the best runtime characteristics for the majority of network
application patterns as long as it is correctly configured. A hashed
timing wheel's worst case is O(n)
where n
is the number of pending
timeouts.
Most useful functions are on Timer
.
Example
Here is a simple example of how to use the timer.
extern crate tokio_timer; extern crate futures; use tokio_timer::*; use futures::*; use std::time::*; pub fn main() { // Create a new timer with default settings. While this is the easiest way // to get a timer, usually you will want to tune the config settings for // your usage patterns. let timer = Timer::default(); // Set a timeout that expires in 500 milliseconds let sleep = timer.sleep(Duration::from_millis(500)); // Use the `Future::wait` to block the current thread until `Sleep` // future completes. // sleep.wait(); }
Hashed Timing Wheel
The hashed timing wheel timer is a coarse grained timer that is optimized for cases where the timeout range is relatively uniform and high precision is not needed. These requirements are very common with network related applications as most timeouts tend to be a constant range (for example, 30 seconds) and timeouts are used more as a safe guard than for high precision.
The timer is inspired by the paper by Varghese and Lauck.
A hashed wheel timer is implemented as a vector of "slots" that represent time slices. The default slot size is 100ms. As time progresses, the timer walks over each slot and looks in the slot to find all timers that are due to expire. When the timer reaches the end of the vector, it starts back at the beginning.
Given the fact that the timer operates in ticks, a timeout can only be as precise as the tick duration. If the tick size is 100ms, any timeout request that falls within that 100ms slot will be triggered at the same time.
A timer is assigned to a slot by taking the expiration instant and assigning it to a slot, factoring in wrapping. When there are more than one timeouts assigned to a given slot, they are stored in a linked list.
This structure allows constant time timer operations as long as timeouts
don't collide. In other words, if two timeouts are set to expire at
exactly num-slots * tick-duration
time apart, they will be assigned to
the same bucket.
The best way to avoid collisions is to ensure that no timeout is set that
is for greater than num-slots * tick-duration
into the future.
A timer can be configured with Builder
.
Runtime details
When creating a timer, a thread is spawned. The timing details are managed
on this thread. When Timer::set_timeout
is called, a request is sent to
the thread over a bounded channel.
All storage needed to run the timer is pre-allocated, which means that the
timer system is able to run without any runtime allocations. The one
exception would be if the timer's max_capacity
is larger than the
initial_capacity
, in which case timeout storage is allocated in chunks as
needed. Timeout storage can grow but never shrink.
Structs
Builder |
Configures and builds a |
Interval |
A stream representing notifications at fixed interval |
Sleep |
A |
Timeout |
Allows a given |
TimeoutStream |
Allows a given |
Timer |
A facility for scheduling timeouts |
Enums
TimeoutError |
The error type for timeout operations. |
TimerError |
The error type for timer operations. |
Functions
wheel |
Configure and build a |