You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/faq.md
+62Lines changed: 62 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -376,6 +376,68 @@ obsolete standards.
376
376
While such legacy code exists, be aware that JavaScript code may require
377
377
special care.
378
378
379
+
### Possible deadlock
380
+
381
+
There are cases where users might encounter an error similar to the following one:
382
+
383
+
> 💀🔒 - Possible deadlock if proxy.xyz(...args) is awaited
384
+
385
+
#### When
386
+
387
+
Let's assume a worker script contains the following *Python* code:
388
+
389
+
```python title="worker: a deadlock example"
390
+
from pyscript import sync
391
+
392
+
sync.worker_task =lambda: print('🔥 this is fine 🔥')
393
+
394
+
# deadlock 💀🔒
395
+
sync.main_task()
396
+
```
397
+
398
+
On the *main* thread, let's instead assume this code:
399
+
```html title="main: a deadlock example"
400
+
<scripttype="mpy">
401
+
from pyscript import PyWorker
402
+
403
+
def asyncmain_task():
404
+
# deadlock 💀🔒
405
+
awaitpw.sync.worker_task()
406
+
407
+
pw =PyWorker("./worker.py", {"type":"pyodide"})
408
+
pw.sync.main_task= main_task
409
+
</script>
410
+
```
411
+
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.
415
+
416
+
#### Workaround
417
+
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.
419
+
420
+
However, if the *main* task does not need to block the *worker* while executing, we can rewrite that code as such:
421
+
422
+
On the *main* thread, let's instead assume this code:
423
+
424
+
```html title="main: avoiding deadlocks"
425
+
<scripttype="mpy">
426
+
from pyscript import window, PyWorker
427
+
428
+
def asyncmain_task():
429
+
# do not await the worker,
430
+
# just schedule it forlater (as resolved)
431
+
window.Promise.resolve(pw.sync.worker_task())
432
+
433
+
pw =PyWorker("./worker.py", {"type":"pyodide"})
434
+
pw.sync.main_task= main_task
435
+
</script>
436
+
```
437
+
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
+
440
+
379
441
## Helpful hints
380
442
381
443
This section contains common hacks or hints to make using PyScript easier.
0 commit comments