use the 'fork' start method for multiprocessing, even on macOS with Python>=3.8#18124
use the 'fork' start method for multiprocessing, even on macOS with Python>=3.8#18124scheibelp merged 16 commits intospack:developfrom
Conversation
… with Python>=3.8
|
For the macOS tests in |
|
I am actively working on #14187 and intend to finish it within a week, so I would be inclined to use that instead of this (for the reason mentioned in the link you provided). |
|
@scheibelp my comment above applies to your PR as well. Let me know if I can help test or anything. Would really love to see this bug fixed soon. |
|
@adamjstewart @scheibelp close this PR. |
|
#18205 is taking longer than desired (although it is still my priority) so I will be reopening this and following the suggestion in #18124 (comment) to run the Mac OS tests with python 3.8. |
|
Found and fixed a few more uses of |
|
I noticed an interesting side effect of this PR. When I run EDIT: Okay, it's not actually a side-effect of this PR. It only occurs with Python 3.8. It's much better than the existing behavior (tests crash). |
I assume when you say "existing behavior" you mean "prior to 42a04f5"?
Also to make sure, it looks like this issue is intermittent? It appears you were able to "make it go away" by just rerunning the tests. |
I mean on develop. But yes, before that commit the tests still crashed.
|
|
Hmm, I think we want to use this method for |
|
@scheibelp the reason I went crazy and wrapped everything was that I didn't trust the unit tests to cover every line of code. I'm happy to revert that commit and go with the bare minimum needed to get the tests to pass. I think most if not all of the calls to |
That is my preference: I think that it's confusing to access |
|
|
||
| args = (b,) + tuple(kwargs.get('extra_args', ())) | ||
| procs = [Process(target=f, args=args, name=f.__name__) | ||
| procs = [fork_context.Process(target=f, args=args, name=f.__name__) |
There was a problem hiding this comment.
This one is definitely required:
AttributeError: Can't pickle local object 'test_lock_debug_output.<locals>.p2'
| input_stream = None # just don't forward input if this fails | ||
|
|
||
| self.process = multiprocessing.Process( | ||
| self.process = fork_context.Process( |
There was a problem hiding this comment.
This one is needed:
E AssertionError: assert False
E + where False = <function exists at 0x101dcbd40>('/private/var/folders/21/hwq39zyj4g36x6zjfyl5l8080000gn/T/pytest-of-Adam/pytest-79/test_foreground_background_tes7/log.txt')
E + where <function exists at 0x101dcbd40> = <module 'posixpath' from '/Users/Adam/.spack/darwin/.spack-env/view/lib/python3.7/posixpath.py'>.exists
E + where <module 'posixpath' from '/Users/Adam/.spack/darwin/.spack-env/view/lib/python3.7/posixpath.py'> = os.path
| input_stream = os.fdopen(os.dup(sys.stdin.fileno())) | ||
|
|
||
| p = multiprocessing.Process( | ||
| p = fork_context.Process( |
There was a problem hiding this comment.
This one is definitely needed, otherwise you can't install anything:
AttributeError: Can't pickle local object 'fork.<locals>.child_process'
|
|
||
| """ | ||
| self.proc = multiprocessing.Process( | ||
| self.proc = fork_context.Process( |
There was a problem hiding this comment.
This one is also needed:
E RuntimeError:
E An attempt has been made to start a new process before the
E current process has finished its bootstrapping phase.
E
E This probably means that you are not using fork to start your
E child processes and you have forgotten to use the proper idiom
E in the main module:
E
E if __name__ == '__main__':
E freeze_support()
E ...
E
E The "freeze_support()" line can be omitted if the program
E is not going to be frozen to produce an executable.
|
@scheibelp alright, I think I removed all non-essential changes from this PR. This should be the smallest possible diff needed to get the tests to pass. Once this is merged, I plan on using Spack with Python 3.8 on macOS, so if there are any other places that need this fix, I'll probably notice them. I think this is ready to merge now if you want to re-review. |
|
Just to keep you posted: since this PR ran a couple of very long-running macOS workflows on GH actions, I aborted all but the last commit to unblock other waiting PRs :) |
|
Thanks @r-xue, @adamjstewart, @tgamblin, and @ax3l for your work on this! |
|
This is wonderful, thank you all! 🚀 ✨ |
|
Thanks @r-xue, what a valuable first-time contribution! |
|
Thanks everyone! |
…ack#18124) As detailed in https://bugs.python.org/issue33725, starting new processes with 'fork' on Mac OS is not guaranteed to work in general. As of Python 3.8 the default process spawning mechanism was changed to avoid this issue. Spack depends on the fork-based method to preserve file descriptors transparently, to preserve global state, and to avoid pickling some objects. An effort is underway to remove dependence on fork-based process spawning (see spack#18205). In the meantime, this allows Spack to run with Python 3.8 on Mac OS by explicitly choosing to use 'fork'. Co-authored-by: Peter Josef Scheibel <[email protected]> Co-authored-by: Adam J. Stewart <[email protected]> Co-authored-by: Todd Gamblin <[email protected]>
This is based on spack@d9b945f without the changes in the .github dir and should be reverted before updating to a new spack version original commit message: Mac OS: support Python >= 3.8 by using fork-based multiprocessing (spack#18124) As detailed in https://bugs.python.org/issue33725, starting new processes with 'fork' on Mac OS is not guaranteed to work in general. As of Python 3.8 the default process spawning mechanism was changed to avoid this issue. Spack depends on the fork-based method to preserve file descriptors transparently, to preserve global state, and to avoid pickling some objects. An effort is underway to remove dependence on fork-based process spawning (see spack#18205). In the meantime, this allows Spack to run with Python 3.8 on Mac OS by explicitly choosing to use 'fork'.
…ack#18124) As detailed in https://bugs.python.org/issue33725, starting new processes with 'fork' on Mac OS is not guaranteed to work in general. As of Python 3.8 the default process spawning mechanism was changed to avoid this issue. Spack depends on the fork-based method to preserve file descriptors transparently, to preserve global state, and to avoid pickling some objects. An effort is underway to remove dependence on fork-based process spawning (see spack#18205). In the meantime, this allows Spack to run with Python 3.8 on Mac OS by explicitly choosing to use 'fork'. Co-authored-by: Peter Josef Scheibel <[email protected]> Co-authored-by: Adam J. Stewart <[email protected]> Co-authored-by: Todd Gamblin <[email protected]> (cherry picked from commit d9b945f) (modified to apply to 0.15.4)
* Backported the fix from spack/spack#18124 to our spack * Switch to that version in our spack.
* Backported the fix from spack/spack#18124 to our spack * Switch to that version in our spack.
Note that it is still the plan to try to make it work with `spawn` as well. Refs: - https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods - https://bugs.python.org/issue40106 - spack/spack#18124
This object was introduced in spack#18124 which was later superseded by spack#18205 and removed any use if the object.
This is intended to fix #14102, only relevant to macOS with Python=3.8.
Python 3.8 in macOS switches to the
spawnstart method in multiprocessing as default, so the resources of the parent process may not be inherited by the child process. Forcing "fork" start might not be a permanent solution (see here), but at least get things working on macOS for now.I came across a similar issue in a different setting, which was reported here.