New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Import dotted name as alias breaks with concurrency #74997
Comments
I noticed this weird behavior in Python 3.6: Apparently Everything seems to be working perfectly fine:
See this repo with code for reproducing the issue: https://github.com/rshk/python36-import-alias-concurrency-bug I tested this on the system Python 3.6.1 shipped with Archlinux (both inside and outside of a virtualenv), and in the official docker image for 3.6. This all started here psycopg/psycopg2#550 as others were experiencing this issue too. |
On other side, bpo-23203 fixed just a symptom. The issue is reproduced in master when replace "import foobar.submodule as foo" with "import foobar.submodule; foo = foobar.submodule". The regression may be related to bpo-22557. Either the optimization introduced a bug, or it exposed an existing bug by changing timings. |
My guess is the import of package has completed but package.submodule hasn't (I don't know what state it would be in, but obviously before the module is assigned as an attribute on the package), a context switch occurs, and then the assignment fails due to package.submodule not being set on package yet. I wonder if package.submodule is in sys.modules when the AttributeError is triggered? I don't remember when the assignment of a submodule to an attriute on a package occurs, but this suggests it's rather late and that's why this is failing. Maybe the assignment is outside of the per-module lock being released and that is what's causing this? Hey, at least importing in a thread doesn't deadlock anymore like it used to. ;) |
Documenting explicitly what I believe the expected order of module lock acquisition would be in this case:
Looking at https://hg.python.org/cpython/rev/64f195790a3a#l4.367 (the commit for bpo-22557), there's a potentially suspect change in the scope of a "_PyImport_AcquireLock/_PyImport_ReleaseLock" pair inside PyImport_ImportModuleLevelObject Specifically, I think we may now have a race condition at https://github.com/python/cpython/blob/master/Python/import.c#L1534, where two threads can *both* end up trying to initialize the same module, since we're no longer holding the global import lock around that "mod = PyDict_GetItem(interp->modules, abs_name);" call and the associated state updates where the first thread indicates that it is already initializing that module so the second thread should just wait for it to finish doing so. |
I have came to the same conclusion. PR 2580 adds a double check in _bootstrap._find_and_load() (and also moves the locking into it). It also simplifies the C code by removing the fast path for the case sys.module[name] is None. |
I just wanted to say thanks to everyone who helped to fix this bug. The locking situation in import is probably the trickiest part of it and has also been tweaked the most as of late and so solving these kinds of issues is tricky. |
test_concurrency() of test_import fails randomly on Windows: see bpo-30891. |
It is worth to backport the test to older versions. Just to be sure that this is a 3.6 regression. |
When running tests from installed location, test_import now fails on master and 3.6 with: ====================================================================== Traceback (most recent call last):
File "/Users/nad/Projects/PyDev/active/dev/3x/root/uxd/lib/python3.7/test/test_import/__init__.py", line 408, in test_concurrency
raise exc
File "/Users/nad/Projects/PyDev/active/dev/3x/root/uxd/lib/python3.7/test/test_import/__init__.py", line 393, in run
import package
ModuleNotFoundError: No module named 'package' |
Which Git revisions are you testing? On master, do you have my latest commit e72b135 ? |
Yes, this is with current top of trunk of both branches. Perhaps I wasn't clear about "installed location". The test does not fail if you run it directly from the build directory like with "make test". It fails when you do a "make install" and then run the test using the newly installed Python. Tests need to work both ways. |
Serhiy on PR 2851:
Oh, too bad that Zach's "x86 Gentoo Installed with X 3.6" buildbot is offline. |
I also opened python/devguide#241 : "Document how to add a new file or a new directory". It's not the first time that we make such mistake. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: