Conversation
|
thank you but we will keep async-hwi using if possible async I/O, we should even migrate our hid libs to async-hid. Claude is better to explain than me also:
|
| Scenario | With reqwest (async) |
With ureq (blocking) |
|---|---|---|
| 100 parallel HTTP requests | Fine — all run concurrently on a few threads | Up to 100 threads blocked simultaneously |
| Mixed async tasks (timers, DB, etc.) | Interleaved normally | Starved while HTTP threads are blocked |
| Tokio worker thread count (e.g. 4) | 4 threads handle thousands of tasks | 4 threads = max 4 concurrent HTTP calls |
The "correct" workaround if you must use ureq
Wrap blocking calls in tokio::task::spawn_blocking:
let response = tokio::task::spawn_blocking(|| {
ureq::get("https://example.com").call()
}).await?;This offloads the blocking work to a dedicated blocking thread pool (separate from Tokio's async workers), so you don't starve the runtime. However:
- Tokio's blocking pool has a default cap of 512 threads — under heavy load, you'll spawn many OS threads
- Each thread has overhead (~8MB stack by default on Linux), so memory usage can spike significantly
- You lose the elegant backpressure and connection pooling that
reqwest+ Tokio gives you for free
Summary recommendation
Stick with reqwest async if you're already on Tokio. It's purpose-built for this:
- Non-blocking, integrates natively with the Tokio reactor
- Connection pooling out of the box
- No thread-per-request overhead
Use ureq only in purely synchronous codebases where you have no async runtime at all. Mixing it with Tokio is technically possible via spawn_blocking, but it trades elegant async concurrency for heavyweight thread-based concurrency, which defeats much of the point of using Tokio in the first place.
this PR replace
reqwestbyureq, it was use in a single call to the Jade ping serverdropping dep count from 278 => 254: