-
Notifications
You must be signed in to change notification settings - Fork 2
/
async_programming.rs
111 lines (93 loc) · 3.15 KB
/
async_programming.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use std::{thread, time};
use std::future::Future;
use std::time::Duration;
use async_std::task;
use futures::{FutureExt, TryFutureExt, TryStreamExt};
use futures::executor::block_on;
pub fn run() {
async_block();
composition();
block_on(parallel_tasks());
async_with_arguments();
}
/**
Provide the execution of a task in one rust [coroutine] returning a [future] of the type specify in the function.
In order to execute in this [coroutine] is as simple as mark the function with async at the beginning.
it's by default lazy execution, and only when you [poll] or wrap it up in a [block_on] function,
is when is executed.
*/
fn async_block() {
let future = async_hello_world()
.map(|v| v.to_uppercase());
let result = block_on(future);
println!("{}", result);
}
async fn async_hello_world() -> String {
String::from("Hello async world")
}
/**
In order to emulate composition of [futures] in rust, we can use await operator, which it will extract
the value from the future, once is ready. This operator it can be used only inside a async function since is a blocking operation.
*/
fn composition() {
let future_program = dependency_c(dependency_b(dependency_a()));
let result = block_on(future_program);
println!("{}", result)
}
async fn dependency_a() -> String {
String::from("Hello ")
}
async fn dependency_b(future_dep_a: impl Future<Output=String>) -> String {
future_dep_a.await + &String::from("Async ")
}
async fn dependency_c(future_dep_b: impl Future<Output=String>) -> String {
future_dep_b.await + &String::from("World ")
}
/**
We can also create futures just running some logic inside async closures.
It will automatically return a [future].
to run both futures in parallel we can use [join] operator which it will merge both result in a tuple (v1,v2)
*/
async fn parallel_tasks() {
let future1 = async {
thread::sleep(time::Duration::from_millis(1000));
String::from("Hello")
};
let future2 = async {
String::from("World")
};
let (v1, v2) = futures::join!(future1,future2);
println!("{} {}", v1, v2)
}
/**
It's also possible pass arguments into a async task using [async move] closure, where the variable
it can be used then in the scope of the future.
*/
fn async_with_arguments() {
let value = String::from("hello world out of Thread");
let future = async move {
println!("Variable:{} in Thread:{:?}", value, thread::current().id())
};
block_on(future)
}
/// In Rust we can also implement [Fire & Forget] pattern.
/// We only need to have an invocation of a async method which return a [Future]
/// Then use this future passing into [async_std::task::spawn]
fn fire_and_forget(){
let future = future_stuff();
let _ = async_std::task::spawn(future);
println!("Continue execution without blocks ${:?}", std::time::Instant::now());
std::thread::sleep(Duration::from_secs(4));
}
async fn future_stuff(){
std::thread::sleep(Duration::from_secs(2));
println!("Hello fire and forget ${:?}", std::time::Instant::now());
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fire_and_forget_test() {
fire_and_forget()
}
}