RuntimeError: cannot release un-acquired lock w/ gevent
Opened this issue · 0 comments
Hi there! Firstly, I want to say that I love this project and pyinstrument
is amazing, thank you! I'm running into a weird issue when running w/ gevent
.
Bug Repro
Env details:
- MBP M3 MAX (Sonoma 14.2.1)
- Python 3.12.1
gevent==24.2.1
,greenlet==3.0.3
,pyinstrument==4.6.2
When I attempt to run pyinstrument against my codebase, it fails when importing a package which monkey-patches the process.
File: pkg_a/init.py
# Patch everything as soon as possible within the package.
import gevent.monkey
gevent.monkey.patch_all()
File: script.py
# All this does is try to import the package
import pkg_a
When run, it emits the following:
$ pyinstrument script.py
Traceback (most recent call last):
File "/Users/vkomarov/dev/divvy-dev/services/collector/env/bin/pyinstrument", line 8, in <module>
sys.exit(main())
^^^^^^
File "/Users/vkomarov/dev/divvy-dev/services/collector/env/lib/python3.12/site-packages/pyinstrument/__main__.py", line 367, in main
exec(code, globs, None)
File "<string>", line 1, in <module>
File "<frozen runpy>", line 286, in run_path
File "<frozen runpy>", line 98, in _run_module_code
File "<frozen runpy>", line 88, in _run_code
File "script.py", line 2, in <module>
import pkg_a
File "<frozen importlib._bootstrap>", line 1357, in _find_and_load
File "<frozen importlib._bootstrap>", line 421, in __exit__
File "<frozen importlib._bootstrap>", line 376, in release
RuntimeError: cannot release un-acquired lock
Expected behavior: It should work w/ gevent appropriately.
My Analysis
It looks like _thread.get_ident()
changes from before the import of the gevent patching code to after. (I verified this by printing out _thread.get_ident()
within pkg_a/__init__.py
). This seems like the direct cause of the RuntimeError
(cpython source).
Then I took a look at what is causing this behavior, since the code runs just fine without it. I narrowed it down to profiler.start()
, but didn't dig any deeper than that.
It should be noted, however, this seems to only happen in a transitive import. i.e.: If I added the monkey patching to script.py
, it works just fine. Also, not patching threading works fine too (it just breaks other parts of our app) (i.e. gevent.monkey.patch_all(thread=False)
).
Any thoughts on this? The only thing I can think of is the Profiler
is doing something with threads in the .start()
method that gevent
monkeypatching doesn't play nice with.