Skip to content
tezvyn:

When should you use asyncio.Lock over threading.Lock?

Source: docs.python.orgMediumHow cards are made

When should you use asyncio.Lock over threading.Lock?

This tests cooperative multitasking knowledge: asyncio.Lock yields to the event loop via await, while threading.Lock blocks the OS thread and freezes the loop. A red flag is claiming threading.Lock works because locks are universal.

What's really being asked

Whether the candidate understands the architectural boundary between asyncio's cooperative single-threaded concurrency and OS-level preemptive threading. Specifically, it checks if they know that asyncio tasks share one thread and yield control explicitly at await points, which means a blocking call like acquiring a threading.Lock will stall the entire event loop rather than just the current task.

The full answer

Four things in order. First, a concrete scenario where an asyncio.Lock is needed, such as multiple tasks incrementing a shared in-memory counter or writing to a shared connection pool between awaitable I/O operations. Second, the mechanism: asyncio.Lock is awaited, so the event loop can switch to another task while the lock is held. Third, the critical difference with threading.Lock: threading.Lock blocks the underlying native thread via OS primitives, which prevents the event loop from scheduling any other coroutine and effectively freezes all tasks. Fourth, the safety caveat from the documentation: asyncio primitives are not thread-safe, and threading primitives are not event-loop-safe, so mixing them is an architectural mismatch.

The mistakes people make

Claiming that a threading.Lock is safe because it is a lock and locks protect shared state, without acknowledging the event loop freeze. Saying that asyncio.Lock is thread-safe or could be used across OS threads. Asserting that because asyncio tasks run on the same thread, no lock is ever needed, which ignores interleaving at await boundaries. Suggesting that using a threading.Lock inside an async function is fine as long as you wrap it in asyncio.to_thread, which misses the point that the question asks about tasks on the same thread.

What usually comes next

How would you share state between an asyncio task and a thread running in an executor? What happens if a task holding an asyncio.Lock is cancelled? How does asyncio.Semaphore differ, and when would you use it instead? Can you use an asyncio.Condition with an asyncio.Lock to coordinate multiple tasks?

A concrete example

Imagine a FastAPI endpoint that caches an access token in a global dictionary. Two concurrent requests hit the cache simultaneously, find it expired, and both try to refresh it. Without an asyncio.Lock, both tasks could pass the expiry check, await an HTTP request to the identity provider, and write duplicate refresh calls. With async with asyncio.Lock(), the first task acquires the lock, awaits the HTTP refresh, updates the dictionary, and releases the lock; the second task awaits the lock, sees the fresh token, and skips the HTTP call. Using threading.Lock here would block the event loop thread during the refresh, pausing all other requests on that worker.

Interview question

What is the primary risk of using threading.Lock inside an asyncio coroutine to guard shared state?

  • a.The lock has no effect since asyncio tasks cannot interleave on a single thread.
  • b.It safely protects the resource because locks are universal synchronization primitives.
  • c.It blocks the underlying OS thread, freezing the event loop and all other tasks.Correct
  • d.The event loop continues scheduling other coroutines while the task waits for the lock.
Why?

threading.Lock blocks the native OS thread via OS primitives, which prevents the event loop from scheduling any other coroutine. Option B is tempting because locks do protect shared state in threaded code, but inside a coroutine a threading.Lock halts the entire loop instead of yielding control.

Just read this? Test yourself on what you have been reading.

Read the original → docs.python.org

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on python — each one lists the topics its interview covers.

See open roles