Skip to content

Commit b926968

Browse files
committed
Update deadlock section in the FAQ.
1 parent 02b2506 commit b926968

File tree

1 file changed

+31
-14
lines changed

1 file changed

+31
-14
lines changed

docs/faq.md

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -378,13 +378,23 @@ special care.
378378

379379
### Possible deadlock
380380

381-
There are cases where users might encounter an error similar to the following one:
381+
Users may encounter an error message similar to the following:
382382

383-
> 💀🔒 - Possible deadlock if proxy.xyz(...args) is awaited
383+
!!! failure
384+
385+
```
386+
💀🔒 - Possible deadlock if proxy.xyz(...args) is awaited
387+
```
384388

385389
#### When
386390

387-
Let's assume a worker script contains the following *Python* code:
391+
This error happens when your code on a worker and in the main thread are
392+
[in a deadlock](https://en.wikipedia.org/wiki/Deadlock). Put simply, neither
393+
fragment of code can proceed without waiting for the other.
394+
395+
#### Why
396+
397+
Let's assume a worker script contains the following Python code:
388398

389399
```python title="worker: a deadlock example"
390400
from pyscript import sync
@@ -395,7 +405,8 @@ sync.worker_task = lambda: print('🔥 this is fine 🔥')
395405
sync.main_task()
396406
```
397407

398-
On the *main* thread, let's instead assume this code:
408+
On the main thread, let's instead assume this code:
409+
399410
```html title="main: a deadlock example"
400411
<script type="mpy">
401412
from pyscript import PyWorker
@@ -409,23 +420,27 @@ pw.sync.main_task = main_task
409420
</script>
410421
```
411422

412-
When the worker bootstraps and locks itself until `main_task()` is completed, it cannot respond to anything at all: it's literally locked.
413-
414-
If the *awaited* task is then asking for *worker* tasks to execute, we are in a clear [deadlock](https://en.wikipedia.org/wiki/Deadlock) situation.
423+
When the worker bootstraps and calls `sync.main_task()` on the main thread, it
424+
blocks until the result of this call is returned. Hence it cannot respond to
425+
anything at all. However, in the code on the main thread, the
426+
`sync.worker_task()` in the worker is called, but the worker is blocked! Now
427+
the code on both the main thread and worker are mutually blocked and waiting
428+
on each other. We are in a classic
429+
[deadlock](https://en.wikipedia.org/wiki/Deadlock) situation.
415430

416-
#### Workaround
431+
The moral of the story? Don't create such circular deadlocks!
417432

418-
Beside trying to avoid deadlocks by all mean is the obvious suggestion and solution, the *blocking* part of the equation is what makes the presented exchange not possible.
433+
How?
419434

420-
However, if the *main* task does not need to block the *worker* while executing, we can rewrite that code as such:
435+
The mutually blocking calls cause the deadlock, so simply don't block.
421436

422-
On the *main* thread, let's instead assume this code:
437+
For example, on the main thread, let's instead assume this code:
423438

424439
```html title="main: avoiding deadlocks"
425440
<script type="mpy">
426441
from pyscript import window, PyWorker
427442
428-
def async main_task():
443+
async def main_task():
429444
# do not await the worker,
430445
# just schedule it for later (as resolved)
431446
window.Promise.resolve(pw.sync.worker_task())
@@ -435,8 +450,10 @@ pw.sync.main_task = main_task
435450
</script>
436451
```
437452

438-
This way it's still possible to consume *worker* exposed utilities within *main* exposed tasks and the worker can happily unlock itself and react to any scheduled task in the meantime.
439-
453+
By scheduling the call to the worker (rather than awaiting it), it's possible
454+
for the main thread to call functions defined in the worker in a non-blocking
455+
manner, thus allowing the worker to also work in an unblocked manner and react
456+
to such calls. We have resolved the mutual deadlock.
440457

441458
## Helpful hints
442459

0 commit comments

Comments
 (0)