rust 如何使用reqwest发出异步请求?

b4lqfgs4  于 2023-10-20  发布在  其他
关注(0)|答案(1)|浏览(126)

我尝试使用Rust的时雄和reqwest crates重新实现以下Python代码。

#!/usr/bin/env python3

import asyncio
import httpx
import time

async def async_req(url, client):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.54",
        "Cookie": ""
    }
    response = await client.get(url, headers=headers, timeout=180)
    print(response.status_code)
    print(response.text)

async def main():
    urls = ["http://localhost:5000/hello", "http://localhost:5000/world"]
    start = time.time()
    async with httpx.AsyncClient() as client:
        tasks = [async_req(url, client) for url in urls]
        await asyncio.gather(*tasks)
    print(time.time()-start)

if __name__ == "__main__":
    asyncio.run(main())

在Rust中实现的代码如下:

async fn async_req(
    url: &str,
    client: reqwest::Client,
) -> Result<reqwest::Response, Box<dyn std::error::Error>> {
    let response = client
        .get(url)
        .timeout(std::time::Duration::from_secs(180))
        .send()
        .await?;

    Ok(response)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let urls = vec![
        "http://localhost:5000/hello",
        "http://localhost:5000/world",
    ];

    let mut handles = vec![];

    let client = reqwest::Client::new();
    for url in urls {
        let handle = {
            let client = client.clone();
            async move { async_req(url, client).await }
        };
        handles.push(handle);
    }

    let mut responses = vec![];
    for handle in handles {
        responses.push(handle.await?);
    }

    for response in responses {
        println!("{}", response.text().await?);
    }

    Ok(())
}

但是看起来这个程序并没有像在Python中那样发出异步请求。
我还没有找到一个不产生错误的解决方案。Cargo.toml的配置如下,我使用的Rust编译器版本是1.72.1(d5 c2 e9 c34,2023-09-13)。

[package]
name = "reqwest_async_demo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
reqwest = { version = "^0.11" }
tokio = { version = "^1", features = [ "full" ] }
zvms9eto

zvms9eto1#

您可以使用tokio::try_join!futures::future::join_all来并发运行期货。这些方法返回一个future,当所有future都完成时,future也完成,并生成所有结果的集合。这类似于Python中asyncio.gather的行为。
首先,将futures crate添加到Cargo.toml

[dependencies]
futures = "0.3"

主要功能:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let urls = vec![
        "http://localhost:5000/hello",
        "http://localhost:5000/world",
    ];

    let client = reqwest::Client::new();
    let mut handles = Vec::new();

    for url in urls {
        let client = client.clone();
        let handle = tokio::spawn(async move { async_req(url, client).await });
        handles.push(handle);
    }

    let responses = futures::future::join_all(handles).await;

    for response in responses {
        match response {
            Ok(Ok(res)) => println!("{}", res.text().await?),
            Ok(Err(e)) => eprintln!("Error: {}", e),
            Err(e) => eprintln!("Error: {}", e),
        }
    }

    Ok(())
}

tokio::spawn用于在新任务中并发地启动每个future,然后futures::future::join_all用于等待所有任务。join_all函数返回一个future,该future解析为传递给它的future结果的Vec

async fn async_req(
    url: &str,
    client: reqwest::Client,
) -> Result<reqwest::Response, reqwest::Error> {
    let response = client
        .get(url)
        .timeout(std::time::Duration::from_secs(180))
        .send()
        .await?;

    Ok(response)
}

相关问题