Executing Multiple Futures at a Time

複数の非同期関数を並行処理する方法の例

join!

join!が返す値は、各Future結果のタプル。1 FutureがResultを返す場合、try_join!がよいらしい。

example

検証時のsleepとして、std::thread::sleepは同期的にブロックしてしまうため、非同期用のsleepが必要。2

tokio::time::sleepを使用した例

Rust Playground

use std::time::Duration;

async fn dance1() { 
    println!("dance1.");
    tokio::time::sleep(Duration::from_secs(10)).await;
    println!("dance1.");
}
async fn dance2() { 
    println!("dance2.");
    tokio::time::sleep(Duration::from_secs(1)).await;
}
async fn dance3() { 
    println!("dance3.");
    tokio::time::sleep(Duration::from_secs(1)).await;
}

#[tokio::main]
async fn main() {
    tokio::join!(dance1(), dance2(), dance3());
}

色々なjoin

色々なjoinがある。差分は不明。対応するランタイムが違うだけならよいが。

source code

select!

基本

複数の非同期処理のうち一つが完了すれば、応じた処理をする。 他の非同期処理の完了は待たない。例えば副作用関数や不純関数の場合はどういう扱いになるのだろうか? select!も式なのでそれぞれの返り値は同じ型でなければならない。

syntax: <pattern> = <expression> => <code>,

select!に渡すFutureはUnpinとfutures::future::FusedFutureを実装する必要がある3 Unpinはselectが可変参照を取得するために必要。moveしては後続処理ができないらしい。 FusedFutureはselectが完了した後にpollしないように必要。FusedFutureは互いに完了したかどうかを追跡する。selectループで完了していないFutureのみpollするために必要。 future::readyによって変えるFutureはFusedFutureを実装しているので、再度pollされないような仕組み。

Streamはfutures::stream::FusedStreamに対応している。

Concurrent tasks in a select loop

futures::future::Fuse::terminatedは既に完了したFutureをFuseできるので、selectループで便利らしい。

source code

Spawning

spawnはJoinHandleを返す。

JoinHandleはFutureを実装しているのでawaitするまで結果を得られない。4

mainタスクとspawnされたタスクとのやり取りとして、channelsを利用する。


1

join! - Asynchronous Programming in Rust
The value returned by join! is a tuple containing the output of each Future passed in.

2

rust - Concurrent async/await with sleep - Stack Overflow
Since the standard/original thread::sleep is blocking, it turns out that the async library is providing async_std::task::sleep( ... ) which is the nonblocking version for sleep.

3

select in futures - Rust
Futures directly passed to select! must be Unpin and implement FusedFuture.

4

Spawning - Asynchronous Programming in Rust
The JoinHandle returned by spawn implements the Future trait, so we can .await it to get the result of the task.