diff --git a/actix-rt/examples/multi_thread_system.rs b/actix-rt/examples/multi_thread_system.rs index 0ecd1ef1..97ab9275 100644 --- a/actix-rt/examples/multi_thread_system.rs +++ b/actix-rt/examples/multi_thread_system.rs @@ -17,44 +17,26 @@ fn main() { // async main function that acts like #[actix_web::main] or #[tokio::main] async fn async_main() { - let (tx, rx) = tokio::sync::oneshot::channel(); - - // get a handle to system arbiter and spawn async task on it - System::current().arbiter().spawn(async { - // use tokio::spawn to get inside the context of multi thread tokio runtime - let h1 = tokio::spawn(async { - println!("thread id is {:?}", std::thread::current().id()); - std::thread::sleep(std::time::Duration::from_secs(2)); - }); - - // work stealing occurs for this task spawn - let h2 = tokio::spawn(async { - println!("thread id is {:?}", std::thread::current().id()); - }); - - h1.await.unwrap(); - h2.await.unwrap(); - let _ = tx.send(()); - }); - - rx.await.unwrap(); - - let (tx, rx) = tokio::sync::oneshot::channel(); - let now = std::time::Instant::now(); - - // without additional tokio::spawn, all spawned tasks run on single thread - System::current().arbiter().spawn(async { + // use System::spawn to get inside the context of multi thread tokio runtime + let h1 = System::spawn(async { println!("thread id is {:?}", std::thread::current().id()); std::thread::sleep(std::time::Duration::from_secs(2)); - let _ = tx.send(()); }); - // previous spawn task has blocked the system arbiter thread - // so this task will wait for 2 seconds until it can be run - System::current().arbiter().spawn(async move { + // work stealing occurs for this task spawn + let h2 = System::spawn(async { println!("thread id is {:?}", std::thread::current().id()); - assert!(now.elapsed() > std::time::Duration::from_secs(2)); }); - rx.await.unwrap(); + h1.await.unwrap(); + h2.await.unwrap(); + + // note actix_rt can not be used in System::spawn + let res = System::spawn(async { + let _ = actix_rt::spawn(actix_rt::task::yield_now()).await; + }) + .await; + + // result would always be JoinError with panic message logged. + assert!(res.is_err()); } diff --git a/actix-rt/src/system.rs b/actix-rt/src/system.rs index 7b15d152..b24e4630 100644 --- a/actix-rt/src/system.rs +++ b/actix-rt/src/system.rs @@ -148,24 +148,27 @@ impl System { /// Send an async task to [System] and spawn running it. /// Returned [JoinHandle](crate::task::JoinHandle) can be used to await for the task's output. /// - /// # Error + /// # Panics + /// Panics if no system is registered on the current thread. + /// + /// # Errors /// [actix_rt::spawn](crate::spawn) can not be used inside `System::spawn`. pub fn spawn(task: T) -> JoinHandle where T: Future + Send + 'static, T::Output: Send + 'static, { + let (tx, rx) = oneshot::channel(); + + CURRENT.with(|cell| match *cell.borrow() { + Some(ref sys) => sys.arbiter_handle.spawn(async { + let res = tokio::spawn(task).await; + let _ = tx.send(res); + }), + None => panic!("System is not running"), + }); + tokio::spawn(async { - let (tx, rx) = oneshot::channel(); - - CURRENT.with(|cell| match *cell.borrow() { - Some(ref sys) => sys.arbiter_handle.spawn(async { - let res = tokio::spawn(task).await; - let _ = tx.send(res); - }), - None => panic!("System is not running"), - }); - // unwrap would be caught by tokio and output as JoinError rx.await.unwrap().unwrap() })