En introduktion till asynkron programmering i rost

Traditionella modeller för synkron programmering leder ofta till prestandaflaskhalsar. Detta beror på att programmet väntar på att långsamma operationer ska slutföras innan de går vidare till nästa uppgift. Detta resulterar ofta i dålig resursanvändning och en trög användarupplevelse.

Asynkron programmering låter dig skriva icke-blockerande kod som utnyttjar systemresurserna effektivt. Genom att utnyttja asynkron programmering kan du designa appar som utför flera uppgifter. Asynkron programmering är praktiskt för att hantera flera nätverksförfrågningar eller bearbeta stora mängder data utan att blockera exekveringsflödet.

Asynkron programmering i rost

Rusts asynkrona programmeringsmodell låter dig skriva effektiv Rustkod som körs samtidigt utan att blockera exekveringsflödet. Asynkron programmering är fördelaktigt när man hanterar I/O-operationer, nätverksförfrågningar och uppgifter som innebär att man väntar på externa resurser.

Du kan implementera asynkron programmering i dina Rust-appar på flera sätt. Dessa inkluderar språkfunktioner, bibliotek och Tokio-körtiden.

Rusts ägarmodell och samtidighetsprimitiver som kanaler och lås möjliggör säker och effektiv samtidig programmering. Du kan utnyttja dessa funktioner med asynkron programmering för att bygga samtidiga system som skalar bra och använder flera CPU-kärnor.

Rusts asynkrona programmeringskoncept

Futures ger en grund för asynkron programmering i Rust. En framtid representerar en asynkron beräkning som inte har utförts helt.

Futures är lata (de blir bara avrättade vid omröstning). När du anropar en future poll()-metod kontrollerar den om framtiden har slutförts eller behöver ytterligare arbete. Om framtiden inte är redo returnerar den Poll::Pending, vilket indikerar att uppgiften ska schemaläggas för senare exekvering. Om framtiden är redo returnerar den Poll::Ready med det resulterande värdet.

Rusts standardverktygskedja inkluderar asynkrona I/O-primitiver, en asynkron version av fil-I/O, nätverk och timers. Dessa primitiver låter dig utföra I/O-operationer asynkront. Detta hjälper till att undvika att blockera ett programs exekvering medan du väntar på att I/O-uppgifter ska slutföras.

Syntaxen async/wait låter dig skriva asynkron kod som liknar synkron kod. Detta gör din kod intuitiv och enkel att underhålla.

Rusts inställning till asynkron programmering betonar säkerhet och prestanda. Reglerna för ägande och lån säkerställer minnessäkerhet och förhindrar vanliga samtidighetsproblem. Async/await-syntax och futures ger ett intuitivt sätt att uttrycka asynkrona arbetsflöden. Du kan använda en runtime från tredje part för att hantera uppgifter för effektiv exekvering.

Du kan kombinera dessa språkfunktioner, bibliotek och körtid för att skriva högpresterande kod. Det ger ett kraftfullt och ergonomiskt ramverk för att bygga asynkrona system. Detta gör Rust till ett populärt val för projekt som kräver effektiv hantering av I/O-bundna uppgifter och hög samtidighet.

Rust version 1.39 och senare versioner stöder inte asynkrona operationer i Rusts standardbibliotek. Du behöver en låda från tredje part för att använda syntaxen async/wait för att hantera asynkrona operationer i Rust. Du kan använda tredjepartspaket som Tokio eller async-std för att arbeta med syntaxen async/await.

Asynkron programmering med Tokio

Tokio är en robust asynkron körtid för Rust. Det ger funktionalitet för att bygga högpresterande och skalbara applikationer. Du kan utnyttja kraften i asynkron programmering med Tokio. Det ger också funktioner för utökningsbarhet.

Kärnan i Tokio är dess asynkrona uppgiftsschemaläggning och exekveringsmodell. Tokio låter dig skriva asynkron kod med syntaxen async/wait. Detta möjliggör ett effektivt utnyttjande av systemresurser och samtidig aktivitetsexekvering. Tokios händelseslinga hanterar effektivt uppgiftsschemaläggning. Detta säkerställer optimalt utnyttjande av CPU-kärnor och minimerar omkostnader för kontextbyte.

Tokios kombinatorer gör uppgiftskoordinering och sammansättning lätt. Tokio tillhandahåller kraftfulla verktyg för uppgiftskoordinering och sammansättning. Du kan vänta på att flera uppgifter ska slutföras med gå med, välj den första avslutade uppgiften med välj och tävla mot varandra med ras.

Lägg till tokio-lådan i din Cargo.toml-fils beroendesektion.

 [dependencies]
tokio = { version = "1.9", features = ["full"] }

Så här kan du använda syntaxen async/wait i dina Rust-program med Tokio:

 use tokio::time::sleep;
use std::time::Duration;

async fn hello_world() {
    println!("Hello, ");
    sleep(Duration::from_secs(1)).await;
    println!("World!");
}

#[tokio::main]
async fn main() {
    hello_world().await;
}

Hello_world-funktionen är asynkron, så den kan använda nyckelordet await för att pausa dess körning tills en framtid är löst. Hello_world-funktionen skriver ut ”Hello,” till konsolen. Funktionsanropet Duration::from_secs(1) avbryter exekveringen av funktionen i en sekund. Nyckelordet vänta väntar på att sömnframtiden ska slutföras. Slutligen skriver funktionen hello_world ut ”World!” till konsolen.

Huvudfunktionen är en asynkron funktion med #[tokio::main] attribut. Den anger huvudfunktionen som startpunkt för Tokio-körtiden. Hello_world().await kör hello_world-funktionen asynkront.

Fördröjande uppgifter med Tokio

En vanlig uppgift i asynkron programmering är att använda fördröjningar eller schemaläggningsuppgifter för att köras inom ett specificerat tidsintervall. Tokios körtid tillhandahåller en mekanism för att använda asynkrona timers och fördröjningar genom tokio::time-modulen.

Så här kan du fördröja en operation med Tokio runtime:

 use std::time::Duration;
use tokio::time::sleep;

async fn delayed_operation() {
    println!("Performing delayed operation...");
    sleep(Duration::from_secs(2)).await;
    println!("Delayed operation completed.");
}

#[tokio::main]
async fn main() {
    println!("Starting...");
    delayed_operation().await;
    println!("Finished.");
}

Funktionen delayed_operation introducerar en fördröjning på två sekunder med vilometoden. Funktionen delayed_operation är asynkron, så den kan använda await för att pausa dess exekvering tills fördröjningen är klar.

Felhantering i asynkrona program

Felhantering i asynkron rostkod innebär att man använder resultattypen och hanterar rostfel med ? operatör.

 use tokio::fs::File;
use tokio::io;
use tokio::io::{AsyncReadExt};

async fn read_file_contents() -> io::Result<String> {
    let mut file = File::open("file.txt").await?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).await?;
    Ok(contents)
}

async fn process_file() -> io::Result<()> {
    let contents = read_file_contents().await?;
    
    Ok(())
}

#[tokio::main]
async fn main() {
    match process_file().await {
        Ok(()) => println!("File processed successfully."),
        Err(err) => eprintln!("Error processing file: {}", err),
    }
}

Funktionen read_file_contents returnerar ett io::Resultat som representerar möjligheten för ett I/O-fel. Genom att använda ? operatör efter varje asynkron operation kommer Tokio-körtiden att sprida fel upp i anropsstacken.

Huvudfunktionen hanterar resultatet med en match-sats som skriver ut en text baserat på resultatet av operationen.

Reqwest använder asynkron programmering för HTTP-operationer

Många populära lådor, inklusive Reqwest, använder Tokio för att tillhandahålla asynkrona HTTP-operationer.

Du kan använda Tokio med Reqwest för att göra flera HTTP-förfrågningar utan att blockera andra uppgifter. Tokio kan hjälpa dig att hantera tusentals samtidiga anslutningar och effektivt hantera resurser.