This topic is not new to developers; these are my personal thoughts.
Async Await
When dealing with I/O-bound operations (such as database queries, API calls, or file operations), using async/await
improves your application’s responsiveness and scalability.
Benefits of Using async/await
- Non-blocking execution: Instead of waiting (blocking) for an operation to finish, async methods allow the application to continue processing other tasks, improving responsiveness.
- Scalability: Since async operations free up threads to handle other requests, your application can process more requests concurrently, leading to better scalability.
- Improved resource utilization: By avoiding thread starvation, async operations reduce unnecessary memory consumption and optimize CPU usage.
What is a Blocking call?
A blocking call in programming refers to an operation that halts execution until it completes, preventing further progress in the application.
In ASP.NET Core, blocking calls can result in:
- Thread Pool Exhaustion:
ASP.NET Core processes requests using a limited number of threads. A blocking call (e.g.,.ToList()
withoutawait
) ties up a thread, preventing it from handling other requests until the operation completes.
This can slow down the system under high load as incoming requests wait for available threads.
In Python FastAPI, blocking calls can lead to:
- Event Loop Blocking:
FastAPI, powered by async frameworks like Uvicorn and Starlette, uses an event-driven model.
A blocking call (e.g., a synchronous database query) halts the event loop, preventing other requests from being processed concurrently.
Why is this a problem?
Reduced Throughput:
Blocking operations limit how many requests the server can handle at the same time, causing slower response times.
Example: If each request blocks for 2 seconds, the server can only handle a few requests at once.Scalability Issues:
In both platforms, async operations allow better scalability by freeing up resources to handle multiple requests concurrently.
Background Worker
If you set up background jobs (e.g., using Redis), you may reduce the need for async operations in your web API, but it depends on the type of workload you’re handling. When you offload time-consuming tasks (like database operations, API calls, or long-running processes) to a background job, the request-response cycle can be completed quickly, improving the responsiveness of your API.
Benefits of Using Background Worker
- Faster API response: Instead of waiting for operations to complete within the HTTP request, the job runs separately in the background.
- No thread blocking needed in API methods: Since a background worker handles the workload, you don’t need to use async/await extensively in your web controllers.
Key Considerations When Using Background Worker
There are some points I think you have to consider when using Background Worker
- Fire-and-forget nature: Background jobs might not provide instant feedback to the user, so they should be used for operations that don’t require an immediate response.
- Error handling: Ensure background jobs have proper logging and retry mechanisms in place.
- Resource allocation: Jobs require resources (CPU, memory), so monitor background workers separately from your API.
- Concurrency: Background job queues (e.g., Redis) allow better concurrency control, processing jobs one by one or in parallel.
When to use Async/Await, When to use BackgroundWorker
For typical CRUD operations, using async/await is still the better choice, while for long-running or non-critical tasks, it’s better to offload them to a background job queue, such as Redis, Azure Functions or AWS Lambda.
Thanks for reading!