I am attempting to reimplement the following Python code using Rust's tokio and reqwest crates.
#!/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())
The code implemented in Rust is as follows:
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(())
}
But it seems that the program is not making asynchronous requests as it does in Python.
I have not yet found a solution that doesn't produce errors. The configuration of Cargo.toml is as follows, and the Rust compiler version I am using is 1.72.1 (d5c2e9c34, 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" ] }
You can use
tokio::try_join!orfutures::future::join_allto concurrently run the futures. These methods return a future that completes when all the futures have completed, and produces a collection of all their results. This is similar to the behavior ofasyncio.gatherin Python.First, add the
futurescrate to yourCargo.toml:main function:
tokio::spawnis used to start each future concurrently in a new task, and thenfutures::future::join_allis used to await all tasks. Thejoin_allfunction returns a future that resolves to aVecof the results of the futures passed to it.