web-dev-qa-db-ja.com

reqwestを使用して並列非同期HTTPGETリクエストを実行するにはどうすればよいですか?

非同期の例 は便利ですが、RustとTokioに慣れていないため、ベクターからのURLを使用して、一度にN個のリクエストを実行する方法を見つけるのに苦労しています。各URLの応答HTMLのイテレータを文字列として作成します。

これはどのように行うことができますか?

6
user964375

Reqwest 0.10現在:

use futures::{stream, StreamExt}; // 0.3.1
use reqwest::Client; // 0.10.0
use tokio; // 0.2.4, features = ["macros"]

const PARALLEL_REQUESTS: usize = 2;

#[tokio::main]
async fn main() {
    let client = Client::new();

    let urls = vec!["https://api.ipify.org", "https://api.ipify.org"];

    let bodies = stream::iter(urls)
        .map(|url| {
            let client = &client;
            async move {
                let resp = client.get(url).send().await?;
                resp.bytes().await
            }
        })
        .buffer_unordered(PARALLEL_REQUESTS);

    bodies
        .for_each(|b| {
            async {
                match b {
                    Ok(b) => println!("Got {} bytes", b.len()),
                    Err(e) => eprintln!("Got an error: {}", e),
                }
            }
        })
        .await;
}

stream::iter(urls)

stream::iter

文字列のコレクションを取得し、それを Stream に変換します。

.map(|url| {

StreamExt::map

ストリーム内のすべての要素で非同期関数を実行し、要素を新しいタイプに変換します。

let client = &client;
async move {

Clientへの明示的な参照を取得し、その参照(元のClientではない)を匿名の非同期ブロックに移動します。

let resp = client.get(url).send().await?;

Clientの接続プールを使用して非同期GET要求を開始し、要求を待ちます。

resp.bytes().await

応答のバイトを要求して待ちます。

.buffer_unordered(N);

StreamExt::buffer_unordered

先物のストリームをそれらの先物の値のストリームに変換し、先物を並行して実行します。

bodies
    .for_each(|b| {
        async {
            match b {
                Ok(b) => println!("Got {} bytes", b.len()),
                Err(e) => eprintln!("Got an error: {}", e),
            }
        }
    })
    .await;

StreamExt::for_each

ストリームを単一のfutureに変換し直し、途中で受信したデータの量を出力してから、futureが完了するのを待ちます。

参照:

21
Shepmaster