Skip to content

Instantly share code, notes, and snippets.

@agronholm
Created June 12, 2024 20:05
Show Gist options
  • Save agronholm/5a8a2773b82369195a308c910566070a to your computer and use it in GitHub Desktop.
Save agronholm/5a8a2773b82369195a308c910566070a to your computer and use it in GitHub Desktop.
Using blocking portal with a loitering event loop thread
import asyncio
import atexit
from contextlib import ExitStack
from anyio.from_thread import start_blocking_portal
exit_stack = ExitStack()
portal = exit_stack.enter_context(start_blocking_portal())
atexit.register(exit_stack.close)
portal.call(asyncio.sleep, 1)
@dhirschfeld
Copy link

Simply running the example.py also hangs for me:

❯ python example.py 
^CException ignored in: <module 'threading' from '/opt/python/envs/dev310/lib/python3.10/threading.py'>
Traceback (most recent call last):
  File "/opt/python/envs/dev310/lib/python3.10/threading.py", line 1537, in _shutdown
    atexit_call()
  File "/opt/python/envs/dev310/lib/python3.10/concurrent/futures/thread.py", line 31, in _python_exit
    t.join()
  File "/opt/python/envs/dev310/lib/python3.10/threading.py", line 1096, in join
    self._wait_for_tstate_lock()
  File "/opt/python/envs/dev310/lib/python3.10/threading.py", line 1116, in _wait_for_tstate_lock
    if lock.acquire(block, timeout):
KeyboardInterrupt: 

@agronholm
Copy link
Author

I only tested this on Python 3.8, and it seems to hang on any later version.

@dhirschfeld
Copy link

A bug in CPython?

@agronholm
Copy link
Author

I think I see the problem. start_blocking_portal() is using a concurrent.futures.ThreadPoolExecutor behind the scenes, and these started using non-daemonic threads in Python 3.9, so atexit callbacks aren't run, leading to a deadlock. I'll need to make it use plain daemonic Thread instead for consistency.

@dhirschfeld
Copy link

I think I see the problem. start_blocking_portal() is using a concurrent.futures.ThreadPoolExecutor behind the scenes, and these started using non-daemonic threads in Python 3.9, so atexit callbacks aren't run, leading to a deadlock. I'll need to make it use plain daemonic Thread instead for consistency.

Nothing is ever as easy as it should be! 😅 I'm glad you could see the root cause as debugging that was definitely outside my experience/expertise!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment