GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — GH-109978: Allow multiprocessing finalizers to run on a separate thread by pitrou · Pull Request #110510 · python/cpython Conversation
|
|
This is an attempt at solving the aforementioned issue (let non-reentrant multiprocessing finalizers run on a separate thread)... but there are complications due to the fact that multiprocessing obviously relies on |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| if thread_was_running: | ||
| # HACK: os.fork() queries the system for the number of running threads. | ||
| # However, Thread.join() only ensures that the Python thread state | ||
| # was destroyed, while the system thread could still be running. | ||
| # Give it time to exit. | ||
| time.sleep(0.001) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
This is a bit unfortunate. @gpshead
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Agreed, this is effectively because our join() has never truely been a join... I filed #110829 to track that, it is probably time to fix that.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I think that it will skip my turn for this one. I touched too many multiprocessing code recently, and I was bitten. Maybe @serhiy-storchaka wants to have a look, he did something like that recently (I recall vaguely). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I haven't tried to understand the whole thing yet, but i've given it a once over to look at the issues this is running into.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| if thread_was_running: | ||
| # HACK: os.fork() queries the system for the number of running threads. | ||
| # However, Thread.join() only ensures that the Python thread state | ||
| # was destroyed, while the system thread could still be running. | ||
| # Give it time to exit. | ||
| time.sleep(0.001) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Agreed, this is effectively because our join() has never truely been a join... I filed #110829 to track that, it is probably time to fix that.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| } | ||
| // XXX This counts the number of system threads, but Python code can only | ||
| // call threading.Thread.join(), which can return before the system thread ended. | ||
| // This function could therefore print a spurious warning in unlucky cases. |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
It's not spurious though, the existence of a thread doing anything is accurately identified as a potential problem. The annoyance that led to this though is that Python didn't provide a concrete way to guarantee a thread has exited.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| while self._pool: | ||
| self._pool.pop().join() |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
What is the difference?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| with self._lock(): | ||
| return self._stopped |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Why is the lock needed for reading an attribute?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| def wait_until_idle(self): | ||
| with self._queue_drained_cond: | ||
| self._queue_drained_cond.wait_for(lambda: self._queue.empty()) |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
| self._queue_drained_cond.wait_for(lambda: self._queue.empty()) | |
| self._queue_drained_cond.wait_for(self._queue.empty) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| # from the work loop. | ||
| assert callable(cb) | ||
| with self._lock: | ||
| if not self._stopped and self._thread is not None: |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Isn't self._thread always None when self._stopped is True?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| finally: | ||
| cb = None |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a reference to _work_loop() or copy the comment? I was confused when I saw this.
Hmm, _work_queue.enqueue_task() is always called from the global enqueue_task()which keeps a reference tocb`, so it perhaps does not help.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| sub_debug('finalizer ignored because different process') | ||
| res = None | ||
| else: | ||
| try: |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
There is already one try a level above. The second try may be not needed, you can simply add finally at the same level after else. The difference is that the finally block will be exececuted in the except case, but I do not see what can be wrong with this.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
FWIW, I'm prioritizing #110848 now, as it should make this PR slightly more robust. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
This PR is stale because it has been open for 30 days with no activity. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
This PR is blocked on its author, has not been touched by a human in more than 3 years, and no longer merges cleanly. Closing to cull the number of open pull requests. Do not reopen this pull request without getting a go-ahead from a triager or core developer on gh-109978. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.