Asynchroniczność w Rust jest realizowana za pomocą Future — obiektu, który reprezentuje pracę, której wynik zostanie uzyskany w przyszłości. Funkcje zadeklarowane za pomocą async fn zwracają anonimową strukturę-generatorem, która implementuje trait Future. Do uruchomienia kodu asynchronicznego używa się runtime'u (np. Tokio lub async-std), ponieważ standardowa biblioteka nie zawiera wbudowanej pętli zdarzeń.
Główne cechy Rust:
Przykład:
use tokio::time::sleep; use std::time::Duration; async fn foo() { println!("Cześć"); sleep(Duration::from_secs(1)).await; println!("Świat!"); } #[tokio::main] async fn main() { foo().await; }
Czy asynchroniczna funkcja w Rust może domyślnie zostać wykonana od razu po wywołaniu? Dlaczego?
Odpowiedź:
Nie. Wywołanie async fn zwraca nie wynik, ale obiekt typu Future (maszyna stanów). Do rzeczywistego wykonania wymagane jest wywołanie .await lub przekazanie Future do runtime'u. Samo wywołanie tworzy jedynie opis zadania, ale go nie wykonuje.
Przykład:
async fn answer() -> u32 { 42 } let fut = answer(); // nie ma tu wykonania, tylko tworzenie future let result = fut.await; // wykonanie zaczyna się tutaj
Historia
.await. Z tego powodu główne wątki działały synchronicznie, co doprowadziło do spadku wydajności i wzrostu czasu reakcji o 3 razy.Historia
Historia
Jeden z członków zespołu zapomniał o ograniczeniach Send/Sync dotyczących typów używanych wewnątrz Future. Przy próbie podzielenia future między wątki aplikacja zakończyła się błędem kompilacji, wymagającym implementacji Send dla określonej struktury, co wymagało przemyślenia architektury przechowywania stanu.