« Rust : async » : différence entre les versions
Aller à la navigation
Aller à la recherche
(Page créée avec « = Exemple simple = Cargo.toml: <nowiki> [dependencies] futures = { version = "0.3.*" } tokio = {version = "0.2.*", features = ["full"] } </nowiki> Explications dans du code: <nowiki> use futures::prelude::*; use tokio::prelude::*; use tokio::task; //The principle of asynchronous programming is to get out of the usual way of programming, //where the program executes from start to finish, blocking on each task. If we have a web server //for example, we may nee... ») |
Aucun résumé des modifications |
||
Ligne 10 : | Ligne 10 : | ||
Explications dans du code: | Explications dans du code: | ||
<nowiki> | <nowiki> | ||
use futures::prelude::*; | use futures::prelude::*; | ||
use tokio::prelude::*; | use tokio::prelude::*; |
Version du 15 novembre 2023 à 16:18
Exemple simple
Cargo.toml:
[dependencies] futures = { version = "0.3.*" } tokio = {version = "0.2.*", features = ["full"] }
Explications dans du code:
use futures::prelude::*; use tokio::prelude::*; use tokio::task; //The principle of asynchronous programming is to get out of the usual way of programming, //where the program executes from start to finish, blocking on each task. If we have a web server //for example, we may need to answer 10k requests at the same time. //We could use threads, and Rust's fearless concurrency; but asynchronous programming is another //way of doing things. // //So, we have asynchronous functions, that we can launch. They return a handler, and we can keep on //executing code, coming back to the handler to see if it yields anything. Only in these //asynchronous function can we use asynchronous things. // //In Rust, we need two things to do that : the "futures" crate, and a Runtime since Rust does not //come with it by default. The most common on is Tokio, which we'll use here. // //We can then do 3 basic operations : start the runtime, spawn a future, and spawn CPU-blocking //intensive operations. // //Of course, most work will happen in futures, this way. We need to be able to offset the execution //of cpu-intensive things to other threads so we don't block at some point in our main thread, otherwise it is all //useless. type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; //1 - Starting the runtime. This is the shortest version, using a trait #[tokio::main] async fn main() { //2.2 Here we finally get the result of it all. app().await.unwrap(); //3.2 Here we execute our CPU-intensive future. otherapp().await.unwrap(); } //1 bis - This is a more complicated way of doing the same: //start the runtime, spawn a future, and block on it to get an answer. fn othermain() { //runtime let mut rt = tokio::runtime::Runtime::new().unwrap(); //future let future = app(); //blocking rt.block_on(future); } async fn our_async_program() { println!("Hello world"); } //2.1 - Here we spawn a future. //We spawn it using 'task' so we can have multiple futures running at once. //Note that this function is asynchronous, too. async fn app() -> Result<()> { let join = task::spawn(our_async_program()); let res = join.await?; Ok(()) } //3.1 - Spawning CPU-intensive tasks. //This fn is CPU-intensive. fn fib_cpu_intensive(n: u32) -> u32 { match n { 0 => 0, 1 => 1, n => fib_cpu_intensive(n - 1) + fib_cpu_intensive(n - 2), } } //So we spawn a blocking future for it. //Note that this is also asynchronous. async fn otherapp() -> Result<()>{ let threadpool_future = task::spawn_blocking(||fib_cpu_intensive(30)); //And await it. threadpool_future.await?; Ok(()) }