Async/.await

15 декември 2020

Паралелизъм и конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Защо искаме конкурентност

Варианти за конкурентност

Kernel space

Варианти за конкурентност

Kernel space

Варианти за конкурентност

Kernel space

Варианти за конкурентност

User space

Варианти за конкурентност

User space

Варианти за конкурентност

User space

Варианти за конкурентност

User space

Варианти за конкурентност

User space

Async/await в Rust

Async/await в Rust

Async/await в Rust

Async/await в Rust

Async/.await в Rust

async функции

1 2 3 4
// връща анонимен тип, който имплементира trait-а `Future<Output = u8>`
async fn five() -> u8 {
    5
}
#![allow(dead_code)]
// връща анонимен тип, който имплементира trait-а `Future`
async fn five() -> u8 {
    5
}
fn main() {}

Async/.await в Rust

async функции

1 2 3 4
// връща анонимен тип, който имплементира trait-а `Future<Output = u8>`
async fn five() -> u8 {
    5
}
#![allow(dead_code)]
// връща анонимен тип, който имплементира trait-а `Future`
async fn five() -> u8 {
    5
}
fn main() {}

Async/.await в Rust

async функции

1 2 3 4
// връща анонимен тип, който имплементира trait-а `Future<Output = u8>`
async fn five() -> u8 {
    5
}
#![allow(dead_code)]
// връща анонимен тип, който имплементира trait-а `Future`
async fn five() -> u8 {
    5
}
fn main() {}

Async/.await в Rust

async функции

1 2 3 4
// връща анонимен тип, който имплементира trait-а `Future<Output = u8>`
async fn five() -> u8 {
    5
}
#![allow(dead_code)]
// връща анонимен тип, който имплементира trait-а `Future`
async fn five() -> u8 {
    5
}
fn main() {}

Async/.await в Rust

async блокове

1 2 3 4 5 6 7 8 9
use std::future::Future;

fn ten() -> impl Future<Output = u8> {
    // връща анонимен тип, който имплементира trait-а `Future<Output = u8>`
    async {
        let x: u8 = five().await;
        x + 5
    }
}
#![allow(dead_code)]
use std::future::Future;

fn ten() -> impl Future {
    // връща анонимен тип, който имплементира trait-а `Future`
    async {
        let x: u8 = five().await;
        x + 5
    }
}
async fn five() -> u8 { 5 }
fn main() {}

Async/.await в Rust

.await

1 2 3 4 5 6 7 8 9 10 11
async fn five() -> u8 {
    5
}

async fn ten() -> u8 {
    five().await + 5
}

fn main() {
    let x = ten().await;
}
error[E0728]: `await` is only allowed inside `async` functions and blocks --> src/bin/main_c247aff303b227bd4f1fa2405d3f7ad357520e11.rs:10:13 | 9 | fn main() { | ---- this is not `async` 10 | let x = ten().await; | ^^^^^^^^^^^ only allowed inside `async` functions and blocks
async fn five() -> u8 {
    5
}

async fn ten() -> u8 {
    five().await + 5
}

fn main() {
    let x = ten().await;
}

Trait Future

1 2 3 4 5 6 7 8 9 10
pub trait Future {
    type Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>;
}

pub enum Poll<T> {
    Ready(T),
    Pending,
}
use std::task::Context;
use std::pin::Pin;

pub trait Future {
    type Output;

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll;
}

pub enum Poll {
    Ready(T),
    Pending,
}

fn main() {}

Trait Future

1 2 3 4 5
async fn foo() {
    println!("foo");
}

let foo_future = foo();
#![allow(unused_variables)]
fn main() {
async fn foo() {
    println!("foo");
}

let foo_future = foo();
}

Trait Future

1 2 3 4 5
async fn foo() {
    println!("foo");
}

let foo_future = foo();
#![allow(unused_variables)]
fn main() {
async fn foo() {
    println!("foo");
}

let foo_future = foo();
}

Trait Future

1 2 3 4 5
async fn foo() {
    println!("foo");
}

let foo_future = foo();
#![allow(unused_variables)]
fn main() {
async fn foo() {
    println!("foo");
}

let foo_future = foo();
}

Trait Future

1 2 3 4 5
async fn foo() {
    println!("foo");
}

let foo_future = foo();
#![allow(unused_variables)]
fn main() {
async fn foo() {
    println!("foo");
}

let foo_future = foo();
}

Изпълнение на future

Future може да се изпълни

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Futures екосистемата

Съвместимост

Futures екосистемата

Съвместимост

Futures екосистемата

Съвместимост

Futures екосистемата

Съвместимост

Демо код

Web crawler, който събира и напечатва линкове към блогове от https://this-week-in-rust.org

Използвани библиотеки

https://github.com/nikolads/rust_async_demo

Синхронно изпълнение

Синхронно изпълнение

Синхронно изпълнение

Синхронно изпълнение

Синхронно изпълнение

Async и блокиращи операции

Async и блокиращи операции

Async и блокиращи операции

Async и блокиращи операции

Async и блокиращи операции

Примитиви за синхронизация

Async и блокиращи операции

Примитиви за синхронизация

Async и блокиращи операции

Примитиви за синхронизация

Async и блокиращи операции

Примитиви за синхронизация

Async и блокиращи операции

Тежки операции

Async и блокиращи операции

Тежки операции

Async и блокиращи операции

Тежки операции

Async и блокиращи операции

Тежки операции

Async и блокиращи операции

Тежки операции

Един примерен вариант е

1 2 3 4 5 6 7 8 9 10 11 12 13 14
let task_handle = async_std::task::spawn(async {
    let (sender, receiver) = async_std::channel::bounded(1);

    std::thread::spawn(move || {
        let result = blocking_op();

        // `block_on` ще върне веднага, защото има място в канала
        async_std::task::block_on(sender.send(result)).unwrap();
    });

    receiver.recv().await
});

let blocking_op_result = task_handle.await;
#![allow(unused_variables)]
fn blocking_op() {}
fn main() {
async_std::task::block_on(async {
let task_handle = async_std::task::spawn(async {
    let (sender, receiver) = async_std::channel::bounded(1);

    std::thread::spawn(move || {
        let result = blocking_op();

        // `block_on` ще върне веднага, защото има място в канала
        async_std::task::block_on(sender.send(result)).unwrap();
    });

    receiver.recv().await
});

let blocking_op_result = task_handle.await;
});
}

Допълнителна информация

async-std

Давахме примери главно за tokio екосистемата, но друга обещаваща библиотека е async-std.
Тя предоставя аналогичен интерфейс на std, но всички функции които нормално са блокиращи в async-std са асинхронни

Въпроси