failed to run two threads using #[tokio::main] macro - rust

I am trying to understand how tokio runtime works, i created two runtimes(on purpose) using #[tokio::main] macro, the first should executes function a() and the second executes function b().
I am assuming that they should be both printing "im awake A" and "im awake B" simultaniosuly forever (since they are calling a function that has a loop async_task), however that is not the case, it only prints "im awake A".
since each runtime has its own thread pool; why they are not running in parallel?
use std::thread;
fn main() {
a();
b();
}
#[tokio::main]
async fn a() {
tokio::spawn(async move { async_task("A".to_string()).await });
}
pub async fn async_task(msg: String) {
loop {
thread::sleep(std::time::Duration::from_millis(1000));
println!("im awake {}", msg);
}
}
#[tokio::main]
async fn b() {
tokio::spawn(async move { async_task("B".to_string()).await });
}

Calling a(); from the synchronous main function will block until a() finishes. Check out the documentation here: https://docs.rs/tokio/1.2.0/tokio/attr.main.html
#[tokio::main]
async fn main() {
println!("Hello world");
}
Equivalent code not using #[tokio::main]
fn main() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
println!("Hello world");
}) }
To get your example to work, main() could also spawn 2 threads that run a, b and wait for them to finish:
fn main() {
let t1 = thread::spawn(|| {
a();
});
let t2 = thread::spawn(|| {
b();
});
t1.join().unwrap();
t2.join().unwrap();
}
EDIT:
Note that a() and b() also do not need to use tokio::spawn as they're already executing in their own async runtime.
#[tokio::main]
async fn a() -> Result<(), JoinError> {
async_task("A".to_string()).await
}
#[tokio::main]
async fn b() {
async_task("B".to_string()).await
}
If you use tokio::spawn in a and b, you would need to await the spawned future, but tokio::spawn(task.await).await is basically the same as just doing task.await.

#[tokio::main] expands to a call to Runtime::block_on(), and as said in its docs (emphasis mine):
This runs the given future on the current thread, blocking until it is complete, and yielding its resolved result.
If you use Runtime::spawn() instead (and make sure not to drop the runtime because it shuts it down), it prints both from A and B correctly:
fn main() {
let _a_runtime = a();
b();
}
fn a() -> tokio::runtime::Runtime {
let runtime = tokio::runtime::Runtime::new().unwrap();
runtime.spawn(async { async_task("A".to_string()).await });
runtime
}
#[tokio::main]
async fn b() {
tokio::spawn(async move { async_task("B".to_string()).await });
}

Take a look at the documentation for the main macro. There's a clue to why this doesn't work there.
Note: This macro can be used on any function and not just the main function. Using it on a non-main function makes the function behave as if it was synchronous by starting a new runtime each time it is called. If the function is called often, it is preferable to create the runtime using the runtime builder so the runtime can be reused across calls.
So you can use it on multiple functions, but what that means is that you need to call each one in a separate main function. You could also manually construct it
fn main() {
let jh1 = std::thread::spawn(|| a());
let jh2 = std::thread::spawn(|| b());
jh1.join().unwrap();
jh2.join().unwrap();
}
async fn async_task(msg: String) {
loop {
tokio::time::sleep(core::time::Duration::from_secs(1)).await;
println!("I'm awake {}", msg);
}
}
#[tokio::main]
async fn a() {
async_task("a".to_owned()).await
}
#[tokio::main]
async fn b() {
async_task("b".to_owned()).await
}

Related

How to initialize thread local variables using async function

I want to initialize thread local variables for all 4 threads at the beginning of the program.
thread_local! {
static local: i32
}
#[tokio::main(worker_threads = 4)]
async fn main() {
// local = get_local().await;
}
Your tokio runtime is configured to have 4 worker threads, your thread local is provided to the main thread but not to the worker threads.
If you intend to initialize the gRPC client just once, a OnceCell could be appropriate:
use once_cell::sync::OnceCell;
pub static CLIENT: OnceCell<hello_world::greeter_client::GreeterClient<tonic::transport::Channel>> =
OnceCell::new();
pub fn client() -> hello_world::greeter_client::GreeterClient<tonic::transport::Channel> {
CLIENT.get().unwrap().clone()
}
#[tokio::main]
async fn main() {
let channel = tonic::transport::Endpoint::new("http://helloworld")
.unwrap()
.connect_lazy();
let client = hello_world::greeter_client::GreeterClient::new(channel);
CLIENT.set(client).unwrap();
main_().await;
}
async fn main_() {
let _ = client()
.say_hello(hello_world::HelloRequest { name: "foo".into() })
.await;
}
pub mod hello_world {
tonic::include_proto!("helloworld");
}
If you want to stick to something more similar to a thread local or you need more control over the client values, then you can use tokio's task local.
It allows you to provide context to tasks, but keep in mind that tokio::spawn introduces new tasks, so this context is lost when you use tokio::spawn.
The following snippet makes a tonic client available through a client() helper function that internally calls .with() on the task local. This function panics if the task local is not set, there is also try_with() which returns a Result if the value is not provided.
use tokio::task_local;
task_local! {
pub static CLIENT: hello_world::greeter_client::GreeterClient<tonic::transport::Channel>
}
pub fn client() -> hello_world::greeter_client::GreeterClient<tonic::transport::Channel> {
CLIENT.with(|c| c.clone())
}
#[tokio::main]
async fn main() {
let channel = tonic::transport::Endpoint::new("http://helloworld")
.unwrap()
.connect_lazy();
let client = hello_world::greeter_client::GreeterClient::new(channel);
CLIENT.scope(client, main_()).await;
}
async fn main_() {
let _ = client()
.say_hello(hello_world::HelloRequest { name: "foo".into() })
.await;
}
pub mod hello_world {
tonic::include_proto!("helloworld");
}

Why do asynchronous tasks (functions) not run unless awaited?

In Rust I have found that an asynchronous task or function (let's even say a future) is not invoked in the runtime unless it is awaited. In other languages such as C# or NodeJS it is possible to define async tasks and run them concurrently as an async task is meant to provide non-blocking IO. For instance:
public Task Run();
public Task ListenToMusic();
public async Task RunAndListenToMusic() {
Task run = Run(); // the task is already running
Task listenToMusic = ListenToMusic(); // the task is already running
await Task.WhenAll(run, listenToMusic);
}
I have tested this mechanism in Rust using a for loop that actually prints out sequential numbers and found that, they are always executed in order, meaning that the second task is run after the first one.
For people like me who are from the world of dotnet or Java, this is a weird behavior. What is actually going on, I searched but I need someone to explain this in a little bit more details and more simply.
Here's some Rust code that is equivalent to your example:
use tokio; // 1.14.0
async fn task1() {
for i in 0..10 {
println!("Task 1: {}", i);
}
}
async fn task2() {
for i in 0..10 {
println!("Task 2: {}", i);
}
}
#[tokio::main]
async fn main() {
let t1 = task1();
let t2 = task2();
tokio::join!(t1, t2);
}
Playground
If you run this code, you will notice that it executes all of task1 before executing task2. This is expected because execution is single-threaded, so task1 will run so long as it doesn't attempt a blocking operation. However if we add blocking operations (here I've used sleep, but the same goes for I/O operations):
use std::time::Duration;
use tokio; // 1.14.0
async fn task1() {
for i in 0..10 {
println!("Task 1: {}", i);
tokio::time::sleep (Duration::from_millis (1)).await;
}
}
async fn task2() {
for i in 0..10 {
println!("Task 2: {}", i);
tokio::time::sleep (Duration::from_millis (1)).await;
}
}
#[tokio::main]
async fn main() {
let t1 = task1();
let t2 = task2();
tokio::join!(t1, t2);
}
Playground
Now we see that operations are interleaved: when a task blocks the other tasks get a chance to run, which is the whole point of async programming.

Calling an async function synchronously with tokio [duplicate]

I am trying to use hyper to grab the content of an HTML page and would like to synchronously return the output of a future. I realized I could have picked a better example since synchronous HTTP requests already exist, but I am more interested in understanding whether we could return a value from an async calculation.
extern crate futures;
extern crate hyper;
extern crate hyper_tls;
extern crate tokio;
use futures::{future, Future, Stream};
use hyper::Client;
use hyper::Uri;
use hyper_tls::HttpsConnector;
use std::str;
fn scrap() -> Result<String, String> {
let scraped_content = future::lazy(|| {
let https = HttpsConnector::new(4).unwrap();
let client = Client::builder().build::<_, hyper::Body>(https);
client
.get("https://hyper.rs".parse::<Uri>().unwrap())
.and_then(|res| {
res.into_body().concat2().and_then(|body| {
let s_body: String = str::from_utf8(&body).unwrap().to_string();
futures::future::ok(s_body)
})
}).map_err(|err| format!("Error scraping web page: {:?}", &err))
});
scraped_content.wait()
}
fn read() {
let scraped_content = future::lazy(|| {
let https = HttpsConnector::new(4).unwrap();
let client = Client::builder().build::<_, hyper::Body>(https);
client
.get("https://hyper.rs".parse::<Uri>().unwrap())
.and_then(|res| {
res.into_body().concat2().and_then(|body| {
let s_body: String = str::from_utf8(&body).unwrap().to_string();
println!("Reading body: {}", s_body);
Ok(())
})
}).map_err(|err| {
println!("Error reading webpage: {:?}", &err);
})
});
tokio::run(scraped_content);
}
fn main() {
read();
let content = scrap();
println!("Content = {:?}", &content);
}
The example compiles and the call to read() succeeds, but the call to scrap() panics with the following error message:
Content = Err("Error scraping web page: Error { kind: Execute, cause: None }")
I understand that I failed to launch the task properly before calling .wait() on the future but I couldn't find how to properly do it, assuming it's even possible.
Standard library futures
Let's use this as our minimal, reproducible example:
async fn example() -> i32 {
42
}
Call executor::block_on:
use futures::executor; // 0.3.1
fn main() {
let v = executor::block_on(example());
println!("{}", v);
}
Tokio
Use the tokio::main attribute on any function (not just main!) to convert it from an asynchronous function to a synchronous one:
use tokio; // 0.3.5
#[tokio::main]
async fn main() {
let v = example().await;
println!("{}", v);
}
tokio::main is a macro that transforms this
#[tokio::main]
async fn main() {}
Into this:
fn main() {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async { {} })
}
This uses Runtime::block_on under the hood, so you can also write this as:
use tokio::runtime::Runtime; // 0.3.5
fn main() {
let v = Runtime::new().unwrap().block_on(example());
println!("{}", v);
}
For tests, you can use tokio::test.
async-std
Use the async_std::main attribute on the main function to convert it from an asynchronous function to a synchronous one:
use async_std; // 1.6.5, features = ["attributes"]
#[async_std::main]
async fn main() {
let v = example().await;
println!("{}", v);
}
For tests, you can use async_std::test.
Futures 0.1
Let's use this as our minimal, reproducible example:
use futures::{future, Future}; // 0.1.27
fn example() -> impl Future<Item = i32, Error = ()> {
future::ok(42)
}
For simple cases, you only need to call wait:
fn main() {
let s = example().wait();
println!("{:?}", s);
}
However, this comes with a pretty severe warning:
This method is not appropriate to call on event loops or similar I/O situations because it will prevent the event loop from making progress (this blocks the thread). This method should only be called when it's guaranteed that the blocking work associated with this future will be completed by another thread.
Tokio
If you are using Tokio 0.1, you should use Tokio's Runtime::block_on:
use tokio; // 0.1.21
fn main() {
let mut runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime");
let s = runtime.block_on(example());
println!("{:?}", s);
}
If you peek in the implementation of block_on, it actually sends the future's result down a channel and then calls wait on that channel! This is fine because Tokio guarantees to run the future to completion.
See also:
How can I efficiently extract the first element of a futures::Stream in a blocking manner?
As this is the top result that come up in search engines by the query "How to call async from sync in Rust", I decided to share my solution here. I think it might be useful.
As #Shepmaster mentioned, back in version 0.1 futures crate had beautiful method .wait() that could be used to call an async function from a sync one. This must-have method, however, was removed from later versions of the crate.
Luckily, it's not that hard to re-implement it:
trait Block {
fn wait(self) -> <Self as futures::Future>::Output
where Self: Sized, Self: futures::Future
{
futures::executor::block_on(self)
}
}
impl<F,T> Block for F
where F: futures::Future<Output = T>
{}
After that, you can just do following:
async fn example() -> i32 {
42
}
fn main() {
let s = example().wait();
println!("{:?}", s);
}
Beware that this comes with all the caveats of original .wait() explained in the #Shepmaster's answer.
This works for me using tokio:
tokio::runtime::Runtime::new()?.block_on(fooAsyncFunction())?;

How can I run a set of functions on a recurring interval without running the same function at the same time using only the standard Rust library?

I would like to use Rust to create a simple scheduler in order to run multiple concurrent functions at a defined time but do not start more if they haven't finished.
For example, if the defined interval is one second, the scheduler should run the functions and don't start more if the previous functions have not returned. The goal is to prevent running the same function multiple times.
I created a working example with Go like this:
package main
import (
"fmt"
"sync"
"time"
)
func myFunc(wg *sync.WaitGroup) {
fmt.Printf("now: %+s\n", time.Now())
time.Sleep(3 * time.Second)
wg.Done()
}
func main() {
quit := make(chan bool)
t := time.NewTicker(time.Second)
go func() {
for {
select {
case <-t.C:
var wg sync.WaitGroup
for i := 0; i <= 4; i++ {
wg.Add(1)
go myFunc(&wg)
}
wg.Wait()
fmt.Printf("--- done ---\n\n")
case <-quit:
return
}
}
}()
<-time.After(time.Minute)
close(quit)
}
Since I didn't find something like Go's NewTicker within the Rust standard library, I used Tokio and came up with this
extern crate futures;
extern crate tokio;
use futures::future::lazy;
use std::{thread, time};
use tokio::prelude::*;
use tokio::timer::Interval;
fn main() {
let task = Interval::new(time::Instant::now(), time::Duration::new(1, 0))
.for_each(|interval| {
println!("Interval: {:?}", interval);
for i in 0..5 {
tokio::spawn(lazy(move || {
println!("I am i: {}", i);
thread::sleep(time::Duration::from_secs(3));
Ok(())
}));
}
Ok(())
})
.map_err(|e| panic!("interval errored; err={:?}", e));
tokio::run(task);
}
The problem I have with this approach is that the tasks don't wait for the previous functions to be called therefore the functions start again no matter if previously they were running, I am missing here something like Go's sync.WaitGroup. What could be used to achieve the same results as in the working example?
Is it possible to achieve this by only using the standard library? This is mainly for learning purposes, probably there is a pretty straightforward way of doing it and I could avoid extra complexity.
In the end, I would like to periodically monitor some sites via HTTP (get just the returned status code) but don't query all of them again until I have all the responses.
Since you want concurrency and will only use the standard library, then you basically must use threads.
Here, we start a thread for every function for every iteration of the scheduler loop, allowing them to run in parallel. We then wait for all functions to finish, preventing ever running the same function twice concurrently.
use std::{
thread,
time::{Duration, Instant},
};
fn main() {
let scheduler = thread::spawn(|| {
let wait_time = Duration::from_millis(500);
// Make this an infinite loop
// Or some control path to exit the loop
for _ in 0..5 {
let start = Instant::now();
eprintln!("Scheduler starting at {:?}", start);
let thread_a = thread::spawn(a);
let thread_b = thread::spawn(b);
thread_a.join().expect("Thread A panicked");
thread_b.join().expect("Thread B panicked");
let runtime = start.elapsed();
if let Some(remaining) = wait_time.checked_sub(runtime) {
eprintln!(
"schedule slice has time left over; sleeping for {:?}",
remaining
);
thread::sleep(remaining);
}
}
});
scheduler.join().expect("Scheduler panicked");
}
fn a() {
eprintln!("a");
thread::sleep(Duration::from_millis(100))
}
fn b() {
eprintln!("b");
thread::sleep(Duration::from_millis(200))
}
You could also make use of a Barrier to start each function in a thread once and then synchronize all of them at the end of execution:
use std::{
sync::{Arc, Barrier},
thread,
time::Duration,
};
fn main() {
let scheduler = thread::spawn(|| {
let barrier = Arc::new(Barrier::new(2));
fn with_barrier(barrier: Arc<Barrier>, f: impl Fn()) -> impl Fn() {
move || {
// Make this an infinite loop
// Or some control path to exit the loop
for _ in 0..5 {
f();
barrier.wait();
}
}
}
let thread_a = thread::spawn(with_barrier(barrier.clone(), a));
let thread_b = thread::spawn(with_barrier(barrier.clone(), b));
thread_a.join().expect("Thread A panicked");
thread_b.join().expect("Thread B panicked");
});
scheduler.join().expect("Scheduler panicked");
}
fn a() {
eprintln!("a");
thread::sleep(Duration::from_millis(100))
}
fn b() {
eprintln!("b");
thread::sleep(Duration::from_millis(200))
}
I wouldn't use either of these solutions, personally. I'd find a crate where someone else has written and tested the code I need.
See also:
Does Rust have an equivalent of Python's threading.Timer?
Is there a way to schedule a task at a specific time or with an interval?
How do I emulate a timer inside an object that will periodically mutate the object?

Threaded calling of functions in a vector

I have an EventRegistry which people can use to register event listeners. It then calls the appropriate listeners when an event is broadcast. But, when I try to multithread it, it doesn't compile. How would I get this code working?
use std::collections::HashMap;
use std::thread;
struct EventRegistry<'a> {
event_listeners: HashMap<&'a str, Vec<Box<Fn() + Sync>>>
}
impl<'a> EventRegistry<'a> {
fn new() -> EventRegistry<'a> {
EventRegistry {
event_listeners: HashMap::new()
}
}
fn add_event_listener(&mut self, event: &'a str, listener: Box<Fn() + Sync>) {
match self.event_listeners.get_mut(event) {
Some(listeners) => {
listeners.push(listener);
return
},
None => {}
};
let mut listeners = Vec::with_capacity(1);
listeners.push(listener);
self.event_listeners.insert(event, listeners);
}
fn broadcast_event(&mut self, event: &str) {
match self.event_listeners.get(event) {
Some(listeners) => {
for listener in listeners.iter() {
let _ = thread::spawn(|| {
listener();
});
}
}
None => {}
}
}
}
fn main() {
let mut main_registry = EventRegistry::new();
main_registry.add_event_listener("player_move", Box::new(|| {
println!("Hey, look, the player moved!");
}));
main_registry.broadcast_event("player_move");
}
Playpen (not sure if it's minimal, but it produces the error)
If I use thread::scoped, it works too, but that's unstable, and I think it only works because it immediately joins back to the main thread.
Updated question
I meant "call them in their own thread"
The easiest thing to do is avoid the Fn* traits, if possible. If you know that you are only using full functions, then it's straightforward:
use std::thread;
fn a() { println!("a"); }
fn b() { println!("b"); }
fn main() {
let fns = vec![a as fn(), b as fn()];
for &f in &fns {
thread::spawn(move || f());
}
thread::sleep_ms(500);
}
If you can't use that for some reason (like you want to accept closures), then you will need to be a bit more explicit and use Arc:
use std::thread;
use std::sync::Arc;
fn a() { println!("a"); }
fn b() { println!("b"); }
fn main() {
let fns = vec![
Arc::new(Box::new(a) as Box<Fn() + Send + Sync>),
Arc::new(Box::new(b) as Box<Fn() + Send + Sync>),
];
for f in &fns {
let my_f = f.clone();
thread::spawn(move || my_f());
}
thread::sleep_ms(500);
}
Here, we can create a reference-counted trait object. We can clone the trait object (increasing the reference count) each time we spawn a new thread. Each thread gets its own reference to the trait object.
If I use thread::scoped, it works too
thread::scoped is pretty awesome; it's really unfortunate that it needed to be marked unstable due to some complex interactions that weren't the best.
One of the benefits of a scoped thread is that the thread is guaranteed to end by a specific time: when the JoinGuard is dropped. That means that scoped threads are allowed to contain non-'static references, so long as those references last longer than the thread!
A spawned thread has no such guarantees about how long they live; these threads may live "forever". Any references they take must also live "forever", thus the 'static restriction.
This serves to explain your original problem. You have a vector with a non-'static lifetime, but you are handing references that point into that vector to the thread. If the vector were to be deallocated before the thread exited, you could attempt to access undefined memory, which leads to crashes in C or C++ programs. This is Rust helping you out!
Original question
Call functions in vector without consuming them
The answer is that you just call them:
fn a() { println!("a"); }
fn b() { println!("b"); }
fn main() {
let fns = vec![Box::new(a) as Box<Fn()>, Box::new(b) as Box<Fn()>];
fns[0]();
fns[1]();
fns[0]();
fns[1]();
}
Playpen

Resources