[−][src]Struct async_executors::TokioTp
feature="tokio_tp"
only.An executor that uses tokio::runtime::Runtime.
Example
The following example shows how to pass an executor to a library function.
use { futures :: { task::{ Spawn, SpawnExt } } , async_executors :: { TokioTp } , tokio::runtime :: { Builder } , std::convert :: { TryFrom } , futures::channel :: { oneshot, oneshot::Sender } , }; fn lib_function( exec: impl Spawn, tx: Sender<&'static str> ) { exec.spawn( async { tx.send( "I can spawn from a library" ).expect( "send string" ); }).expect( "spawn task" ); } fn main() { // You provide the builder, and async_executors will set the right scheduler. // Of course you can set other configuration on the builder before. // let exec = TokioTp::try_from( &mut Builder::new() ).expect( "create tokio threadpool" ); let program = async { let (tx, rx) = oneshot::channel(); lib_function( &exec, tx ); assert_eq!( "I can spawn from a library", rx.await.expect( "receive on channel" ) ); }; exec.block_on( program ); }
Drop order.
TokioTp bundles an Arc<Mutex<tokio::runtime::Runtime>>
with a tokio::runtime::Handle
.
Doing so has some nice properties. The type behaves similarly to other wrapped executors in
this crate. It implements all the spawn traits directly and is self contained. That means
you can pass it to an API and holding the type means it's valid. If we give out just a
tokio::runtime::Handle
, it can only be used to spawn tasks as long as the Runtime
is
alive.
However, a new problem arises. Runtime
should never be dropped from async context. Since we
use a reference counted Runtime
, the last one actually invokes drop, and if that last one is
in async context, it panics the thread. If you pass a clone into some async task and that tasks
is not properly synchronized, it might outlive the code in non-async context that spawned it.
Now drop happens in async context and boom.
To solve this you can either make sure all tasks are properly synchronized (eg. await JoinHandle
s
so no tasks containing an executor outlive the parent), or hand out TokioHandle which can be
obtained from TokioTp::handle
and which implements all required traits to spawn.
Unwind Safety.
You must only spawn futures to this API that are unwind safe. Tokio will wrap it in std::panic::AssertUnwindSafe and wrap the poll invocation with std::panic::catch_unwind.
They reason that this is fine because they require Send + 'static
on the future. As far
as I can tell this is wrong. Unwind safety can be circumvented in several ways even with
Send + 'static
(eg. parking_lot::Mutex
is Send + 'static
but !UnwindSafe
).
You should make sure that if your future panics, no code that lives on after the spawned task has unwound, nor any destructors called during the unwind can observe data in an inconsistent state.
Note that these are logic errors, not related to the class of problems that cannot happen in safe rust (memory safety, undefined behavior, unsoundness, data races, ...). See the relevant catch_unwind RFC and it's discussion threads for more info as well as the documentation of std::panic::UnwindSafe.
Implementations
impl TokioTp
[src]
pub fn block_on<F: Future>(&self, f: F) -> F::Output
[src]
Wrapper around Runtime::block_on.
pub fn handle(&self) -> TokioHandle
[src]
Obtain a handle to this executor that can easily be cloned and that implements the Spawn trait.
This handle only works as long as the parent executor is still alive.
Trait Implementations
impl Clone for TokioTp
[src]
impl Debug for TokioTp
[src]
impl Spawn for TokioTp
[src]
fn spawn_obj(&self, future: FutureObj<'static, ()>) -> Result<(), SpawnError>
[src]
fn status(&self) -> Result<(), SpawnError>
[src]
impl<Out: 'static + Send> SpawnHandle<Out> for TokioTp
[src]
fn spawn_handle_obj(
&self,
future: FutureObj<'static, Out>
) -> Result<JoinHandle<Out>, SpawnError>
[src]
&self,
future: FutureObj<'static, Out>
) -> Result<JoinHandle<Out>, SpawnError>
impl<'_> TryFrom<&'_ mut Builder> for TokioTp
[src]
Auto Trait Implementations
impl !RefUnwindSafe for TokioTp
impl Send for TokioTp
impl Sync for TokioTp
impl Unpin for TokioTp
impl !UnwindSafe for TokioTp
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T> Instrument for T
[src]
fn instrument(self, span: Span) -> Instrumented<Self>
[src]
fn in_current_span(self) -> Instrumented<Self>
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<Sp> SpawnExt for Sp where
Sp: Spawn + ?Sized,
[src]
Sp: Spawn + ?Sized,
fn spawn<Fut>(&self, future: Fut) -> Result<(), SpawnError> where
Fut: Future<Output = ()> + Send + 'static,
[src]
Fut: Future<Output = ()> + Send + 'static,
fn spawn_with_handle<Fut>(
&self,
future: Fut
) -> Result<RemoteHandle<<Fut as Future>::Output>, SpawnError> where
Fut: Future + Send + 'static,
<Fut as Future>::Output: Send,
[src]
&self,
future: Fut
) -> Result<RemoteHandle<<Fut as Future>::Output>, SpawnError> where
Fut: Future + Send + 'static,
<Fut as Future>::Output: Send,
impl<T> ToOwned for T where
T: Clone,
[src]
T: Clone,
type Owned = T
The resulting type after obtaining ownership.
fn to_owned(&self) -> T
[src]
fn clone_into(&self, target: &mut T)
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]
impl<T> WithSubscriber for T
[src]
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> where
S: Into<Dispatch>,
[src]
S: Into<Dispatch>,