MicroPython for Microcontrollers Module 6
Concurrency on devices: asyncio and threads interview questions
Interview questions on “Concurrency on devices: asyncio and threads”: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What does await asyncio.sleep_ms(0) do in a MicroPython task, and when would you write it?
Answered in the lesson asyncio on a microcontroller: tasks and sleeps
-
Fresher
Why must an interrupt handler set a ThreadSafeFlag, rather than an asyncio Event, to wake a task?
-
Fresher to mid
In MicroPython's asyncio, what is the difference between writer.close() and await writer.wait_closed()?
Answered in the lesson Streams, timeouts and cancellation for I/O
-
Fresher to mid
What does sys.implementation._thread tell you, and which values can it have?
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A Pico W runs three asyncio tasks: a status LED that blinks every 100 ms, an MQTT client that sends a reading every minute, and a soil sensor read every 5 seconds. Every few minutes the LED freezes for about 2 seconds, then carries on. How do you find the cause, and what do you change?
- What it tests
- Finding a blocking call among cooperative tasks, measuring lateness instead of guessing, and fixing each kind of block: sleeps, polling drivers, long work and network calls.
- First step
- Measure before guessing. Make the LED task record how late each wake-up is, with ticks_diff() against the time it asked for, and log the worst value with what the other tasks were doing. A 2-second freeze means one task held the loop for 2 seconds without awaiting anything that had to wait.
- Follow-ups
-
- The freezes line up with MQTT reconnects. Why would a reconnect hold the loop?
- The sensor driver polls a ready bit in a while loop. How do you change it?
- How would you prove the fix in a test on your computer?
From the lesson asyncio on a microcontroller: tasks and sleeps
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
You port a CPython asyncio program to a Pico. It calls asyncio.wait_for(asyncio.sleep(5), 1), passes readings through asyncio.Queue(20), runs its workers in an asyncio.TaskGroup, and relies on asyncio.run() cancelling its tasks at exit so that a finally block switches a heater off. What breaks on MicroPython 1.29, and how do you rewrite each part?
- What it tests
- Knowing where MicroPython's asyncio differs from CPython's, and rewriting each part so that the same code runs on both and the heater is always switched off.
- First step
- Check each call against MicroPython's asyncio, which has Event, ThreadSafeFlag, Lock, gather() and wait_for() but no Queue, Semaphore, TaskGroup or timeout(). The wait_for() line fails first: sleep() returns a shared object that is not a coroutine, so wait_for() refuses it until the sleep is wrapped in an async def function.
- Follow-ups
-
- How do you make sure the heater is off whenever the program stops?
- What replaces the TaskGroup's cancelling of the other workers when one fails?
- How do you keep one code base that runs on both CPython and the board?
From the lesson asyncio on a microcontroller: tasks and sleeps
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A hard timer interrupt samples a vibration sensor 1,000 times a second on a Pico W. An asyncio task must publish a one-second average over MQTT, and a publish can take up to 300 ms when Wi-Fi is weak. Design the hand-off from the interrupt to the task, and say how you know that no sample is lost.
- What it tests
- The hand-off from an interrupt to asyncio with ThreadSafeFlag and a ring buffer, sizing the buffer from the worst delay, and proving with counters that nothing is lost.
- First step
- Keep the interrupt tiny: read the ADC, store the value in a ring made at start-up, count a drop when it is full, and set a ThreadSafeFlag. Then size the ring from the longest the task can be late: at 1,000 samples a second, a 300 ms publish leaves 300 samples waiting, so the ring needs well over 300 slots.
- Follow-ups
-
- Why not call Event.set() in the interrupt handler?
- What changes if a publish sometimes takes 2 seconds?
- How do you test the hand-off without the board?
From the lesson Events, locks and ThreadSafeFlag
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
Two asyncio tasks draw on one I2C OLED display: one writes the temperature, the other a menu, each in several awaited steps that send parts of the frame. Now and then the screen shows half of each. Explain why, and choose between an asyncio.Lock, one display task fed by a queue, and an Event.
- What it tests
- Seeing an update torn across awaits, and choosing how tasks share a device: a lock, one owner task with a queue, or a signal.
- First step
- Find the awaits inside each drawing sequence. A task gives the loop away at each one, so the other task can start drawing in the middle of a frame. Code between two awaits is never interleaved, so each frame must reach the display whole: one task at a time inside it, or one task that owns it.
- Follow-ups
-
- What does the Lock cost the menu task?
- Why can an Event not fix this on its own?
- When is one display task the better design?
From the lesson Events, locks and ThreadSafeFlag
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An ESP32 posts a reading to a server every minute with asyncio streams. When the server is down for an hour, the board stops answering its button, its LED freezes now and then, and after a while it resets. Explain what is going on, and design the client so that a dead server costs no more than a log line.
- What it tests
- Deadlines on every network wait, reconnecting with a capped back-off, closing sockets on every path, and keeping blocking calls out of the loop.
- First step
- Look for waits without a deadline and for resources that are not given back. A readline() on a server that accepts and never answers waits for ever, a reconnect loop that retries at once floods the loop, every try that ends with close() alone leaves a socket open, and the name lookup inside open_connection() blocks every task.
- Follow-ups
-
- Which symptom is the socket leak, and how do you see it on the board?
- How long should each deadline be?
- What should the watchdog watch?
From the lesson Streams, timeouts and cancellation for I/O
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
On shutdown, an app cancels a task that has a pump relay switched on and a socket open. Walk through what happens from task.cancel() to the end of the task, and name the mistakes that leave the pump running.
- What it tests
- How a cancel is delivered at an await, the part finally plays, BaseException and bare except clauses, and what awaiting the task and wait_for_ms() add.
- First step
- cancel() does not stop the task on the spot. The loop throws CancelledError into it at the await where it waits; from there the exception travels outward through the task's except and finally blocks and ends the task, unless a block catches it.
- Follow-ups
-
- What if the task is inside wait_for_ms() when it is cancelled?
- How does main know that the relay is off?
- What if the finally block itself awaits something slow?
From the lesson Streams, timeouts and cancellation for I/O
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A Pico W must sample a vibration sensor every 500 µs without a gap, and keep a Wi-Fi connection and an MQTT session at the same time. Would you use asyncio, a hard timer interrupt or the second core, and how would the parts share data?
- What it tests
- Matching each job to a way of running it, the timing each way can keep, and a safe hand-off between the cores or between an interrupt and a task.
- First step
- Work out the budget first: 500 µs is 2,000 samples a second, far tighter than the tens of milliseconds an asyncio task can be late. So the sampling cannot be an asyncio task: it is a hard timer handler or a loop on core 1, and the network stays in asyncio on core 0.
- Follow-ups
-
- What decides between the hard interrupt and core 1?
- How big must the buffer between them be?
- How do you show that no sample is lost?
From the lesson _thread and the second core
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
Code that counts events in two threads gives the right totals on an ESP32 but loses counts on a Pico. Explain why, and how you would make it correct on both.
- What it tests
- The GIL and unsafe models, why count += 1 is several steps, and locks that keep shared updates whole on every port.
- First step
- Compare sys.implementation._thread on the two boards. The ESP32 build has a GIL, so one thread runs Python at a time and a short count += 1 is never split; the Pico has none, so both cores run at once and the four steps of count += 1 can interleave.
- Follow-ups
-
- Why might the ESP32 lose counts one day too?
- What does the lock cost, and how do you keep that small?
- Could each thread keep a count of its own instead?
From the lesson _thread and the second core
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
All MicroPython for Microcontrollers interview questions · The MicroPython for Microcontrollers track