Asynchronous Programming in PYthon - Interview Questions and Answers

Asynchronous programming allows code to run independently of the main thread, enabling concurrent operations using async and await without blocking.

Async code runs in a single thread using non-blocking IO; threading and multiprocessing use system-level threads and processes for concurrency.

async defines an asynchronous function, and await pauses the function until the awaited task completes.

The event loop manages and executes asynchronous tasks, coordinating coroutine execution.

Define a function using async def, and call it using await inside an async context.

Coroutines can pause and resume using await, while normal functions execute linearly.

Use asyncio.run(coro()) or create an event loop and run tasks manually.

It provides tools for writing single-threaded concurrent code using coroutines, tasks, and the event loop.

No, await must be inside a function declared with async def.

Tasks wrap coroutines and allow them to be scheduled in the event loop.

It runs multiple coroutines concurrently and waits for all of them to finish.

It pauses a coroutine without blocking the event loop.

Both schedule coroutines, but create_task() is preferred in modern Python (3.7+); ensure_future() works with both coroutines and futures.

Yes, exception handling works the same way as in regular functions.

Any object that can be awaited—includes coroutines, asyncio.Future, or any object with __await__().

A TypeError is raised.

Use task.cancel() and await it to propagate asyncio.CancelledError.

Use asyncio.wait_for(coro, timeout=5).

A low-level awaitable representing a result that may not be available yet.

Use loop.run_in_executor() to run synchronous/blocking code in a thread or process pool.

Exceptions raised inside async functions propagate like regular exceptions.

  • Coroutine: A function defined with async def.
  • Future: An object representing a pending result.
  • Task: A coroutine wrapped to run in an event loop.

It refers to the model where tasks yield control voluntarily using await, unlike preemptive multitasking.

Yes, using asyncio.run() or event loop methods.

It’s an asynchronous HTTP client/server library built on asyncio.

It creates a new event loop, runs the coroutine, and closes the loop upon completion.

Async uses fewer resources and avoids thread-switching overhead.

No, async is best for IO-bound tasks; use multiprocessing for CPU-bound work

Modular coroutines, clear separation of async and sync logic, and use of asyncio.gather() for concurrency.

Yes, async functions can call synchronous ones, but not the reverse.

Use async with for asynchronous context managers that need to await setup/teardown.

It allows iteration over asynchronous iterators.

A generator defined using async def and yield, can be iterated with async for.

Use pytest with pytest-asyncio or use asyncio’s loop.run_until_complete() in unittest.

Wrap each task with try-except or use return_exceptions=True in asyncio.gather().

Can be hard to debug, not suitable for CPU-bound work, steep learning curve.

Simply await one async function inside another async function.

For managing resources asynchronously like file streams, HTTP sessions, or DB connections.

Trio is a modern async library with structured concurrency; aims for better error handling and easier cancellation.

Yes, just like synchronous functions, but you must await recursive calls.

Tasks voluntarily yield control using await to allow other tasks to run.

Use logging, asyncio.run(), loop.set_debug(True), or IDEs that support coroutine tracing.

Prevents a coroutine from being cancelled even if the outer coroutine is.

Points where coroutine execution can be interrupted, like await.

When coroutines are waiting on each other, and none progress.

Use try/finally to handle cleanup and propagate CancelledError.

Yes, you can run the event loop in one thread and interact using run_in_executor().

Use asyncio.wait_for() or custom timeouts with asyncio.gather().

Objects that implement __aiter__() and __anext__() for asynchronous iteration.

Async is function-driven concurrency; reactive is stream-based event processing (e.g., RxPy).