How it works...

Let's start by introducing the Future trait: 

  • Implementing the Future trait requires only three constraints: an Item  type, an Error type, and a poll() function. The actual trait looks as follows:
pub trait Future {
type Item;
type Error;
fn poll(
&mut self,
cx: &mut Context
) -> Result<Async<Self::Item>, Self::Error>;
}
  • The Poll<Self::Item, Self::Error> is a type that translates into Result<Async<T>, E> , where T = Item and E = Error. This is what our example is using on line 50.
  • poll() is called upon whenever a futures::task::Waker (can also be known as a Task) is executed with one of our executors located at futures::executor, or manually woken up by building a futures::task::Context and running with a future wrapper such as futures::future::poll_fn.

Now, onto our local_until() function:

  • LocalPool offers us the ability to run tasks concurrently using a single thread. This is useful for functions with minimal complexity, such as traditional I/O bound functions. LocalPools can have multiple LocalExecutors (as we have created one on line 65), which can spawn our task. Since our task is single-threaded, we do not need to Box or add the Send trait to our future. 
  • The futures::future::lazy function will create a new future, from a FnOnce closure, which becomes the same future as the one that the closure returns (any futures::future::IntoFuture trait), which in our case that future is FutureResult<Container, Never>.
  • Executing the run_until(F: Future) function from the LocalPool will perform all of the future tasks until the Future (indicated as F) has been marked as completed. This function will return Result<<F as Future>::Item, <F as Future>::Error> upon completion. In the example, we are returning futures::future::ok(Container), on line 75, so our F::Item will be our Container.

For our local_spawns_completed() function:

  • First, we set up our futures::channel::oneshot channel (which is explained later, in the Using the oneshot channel section).
  • We will use the oneshot channel's futures::channel::oneshot::Receiver as the future to run until completion within the run_until() function. This allows us to demonstrate how polling would work until a signal has been received from another thread or task (in our example, this happens on line 102 with the tx.send(...) command).
  • The LocalExecutor's spawn_local() is a special spawn function that gives us the capability of executing future functions without implementing the Send trait.

Next, our local_nested() function:

  • We set up our usual Container and then declare a reference counter that will allow us to keep a value (this would be our Container) across multiple executors or threads. We do not need to use an atomic reference counter, since we are using spawn_local(), which performs the future on a green thread (a thread that is scheduled by a virtual machine or a runtime library).
  • The LocalPool's run(exec: &mut Executor) function will run any futures spawned within the pool until all of the futures have been completed. This also includes any executors that may spawn additional tasks within other tasks, as our example shows.

Onto our thread_pool() function:

  • An std::sync::mspc::sync_channel is created with the intention of blocking the thread for demonstration purposes.
  • Next, we created a ThreadPool with default settings and called its spawn(F: Box<Future<Item = (), Error = Never> + 'static + Send>) function, which will poll the task until completion whenever we decide to execute the pool.
  • After setting up our tasks, we execute the ThreadPool's run(F: Future) function, which will block the thread in which is invoking run() until the F: Future has been completed. The function will return a value upon the future's completion even if there are other tasks spawned, and running, within the pool.  Using the mspc::sync_channel earlier helps mitigate this issue, but will block the thread upon being invoked.
  • With the ThreadPoolBuilder , you can:
    • Set the number of worker threads
    • Adjust the stack size
    • Set a prefixed name for the pools
    • Run a function (with the signature as Fn(usize) + Send + Sync + 'static) after each worker thread has started, right before the worker thread runs any tasks
    • Execute a function (with the signature as Fn(usize) + Send + Sync + 'static) before each worker thread shuts down
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.228.88