Reputation: 21496
I would like to know if the answer to this rather old question about futures still applies to the more recent language constructs async/await
. It seems to be so, since code below prints:
hello
good bye
hello
although the guide says
The futures::join macro makes it possible to wait for multiple different futures to complete while executing them all concurrently.
Clearly, it's a diversion of the expected behavior in many, many other asynchronous systems (node.js for example), with regard to sleep
.
Any fundamental reason to be that way?
use std::time::Duration;
use std::thread;
async fn sayHiOne() {
println!( " hello " );
thread::sleep( Duration::from_millis( 3000 ) );
println!( " good bye " );
} // ()
async fn sayHiTwo() {
println!( " hello " );
} // ()
async fn mainAsync() {
let fut1 = sayHiOne();
let fut2 = sayHiTwo();
futures::join!( fut1, fut2 );
} // ()
fn main() {
block_on( mainAsync() );
} // ()
Addition: the behavior (I) expected with actual threads
fn main() {
let fut1 = do_async( move || {
println!( "hello" );
thread::sleep( Duration::from_millis( 3000 ) );
println!( "good bye" );
});
let fut2 = do_async( move || {
println!( "hello" );
});
fut1();
fut2();
}
use std::thread;
use std::time::Duration;
use std::sync::mpsc::channel;
fn do_async<TOut, TFun>( foo: TFun ) -> (impl FnOnce()-> TOut)
where
TOut: Send + Sync + 'static,
TFun: FnOnce() -> TOut + Send + Sync + 'static
{
let (sender, receiver)
= channel::< TOut >();
let hand = thread::spawn(move || {
sender.send( foo() ).unwrap();
} );
let f = move || -> TOut {
let res = receiver.recv().unwrap();
hand.join().unwrap();
return res;
};
return f;
} // ()
Upvotes: 3
Views: 11872
Reputation: 21496
Since the standard/original thread::sleep
is blocking, it turns out that the async library is providing async_std::task::sleep( ... )
which is the nonblocking version for sleep. It's to be used with .await
(no parentheses):
task::sleep(Duration::from_millis(3000)).await;
This sleep
has the same effect that unstable version: yield_now in the sense that it
moves the currently executing future to the back of the execution queue, making room for other futures to execute. This is especially useful after running CPU-intensive operations inside a future.
So I guess, the intended use is to "kindly" share the use of the thread among the futures, whenever a task is planning to perform a long work.
Upvotes: 6
Reputation: 1240
Yes, it still applies. It fundamentally has to be that way because, like the linked answer says, each async function will be running on the same thread - std::thread::sleep
knows nothing about async, and so will make the whole thread sleep.
Nodejs (and JavaScript in general) is much more designed around async, so the language primitives and the language runtime are more async-aware in that way.
Upvotes: 2