ENH: delegate runtime resource cleanup to resource_tracker#228
ENH: delegate runtime resource cleanup to resource_tracker#228ogrisel merged 33 commits intojoblib:masterfrom
Conversation
The resource tracker is now in charge of cleaning up shared resources between between Python processes. It does so by reference counting objects each time a Python process demands it (this means the Python process sends a "REGISTER"/"UNREGISTER" request to the resource_tracker). If an object's refcount drops to 0, the resource tracker cleans it up. Previously, Python processes themselves would clean up the shared objects, and the resource_tracker would only intervene at the end of the program when all other processes connected to it have exited.
There was a problem hiding this comment.
Reviewing myself to not forget anything because I'm about to do something else afterwards. @ogrisel it's still WIP but feel free to take a look.
ogrisel
left a comment
There was a problem hiding this comment.
Thinking about it I think we should still preserve the existing behavior with "at exit" cleanup of registered resources by default. Un-registering should not trigger cleanups but instead make sure that the resource tracker does not collect the resource at all.
So instead we should probably add a new method for handling the "decref" with optional cleanup when the refcounts drops to 0. This new method could be called def maybe_cleanup(self, name).
The incref part can still be achieved via the "register" method (no need to introduce a new method).
|
The module docstring uses the |
ogrisel
left a comment
There was a problem hiding this comment.
Some comments on typos / wording improvements.
| _CLEANUP_FUNCS = { | ||
| 'folder': shutil.rmtree | ||
| 'folder': shutil.rmtree, | ||
| 'file': os.unlink |
There was a problem hiding this comment.
Maybe we should wrap those functions to ignore OSError (no such file or directory) if the resource has already been unlinked by another process.
There was a problem hiding this comment.
I agree It would make some test logs less verbose, but I'm not sure about this change yet because it is useful information to know when we overshoot the number of maybe_cleanup calls, especially as I am calibrating the reference counting process of shared numpy arrays in joblib.
|
I still have to push the |
now that unregister conserves its previous behavior, there is no reason to change the semaphores finalizer.
| while True: | ||
| line = f.readline() | ||
| if line == b'': # EOF | ||
| break |
There was a problem hiding this comment.
Question: why no for loop anymore?
There was a problem hiding this comment.
Using a for-loop, in Python 2, the resource_tracker would wait until it got EOF before iterating over the lines written inside the pipe, processing them all at once (during shutdown). This is a bug that is actually present in loky master (but only for Python 2). I have not looked whether this behavior was documented or not.
3f3e410 to
f88ed6d
Compare
608abff to
c3d383e
Compare
* also reduce test output verbosity
| ) | ||
| p.wait() | ||
| out, err = p.communicate() | ||
| assert p.returncode == 0, err |
There was a problem hiding this comment.
If the test errors, using this syntax instead of check_output leads to a much cleaner error reporting.
|
@ogrisel all tests are passing. Only |
ogrisel
left a comment
There was a problem hiding this comment.
The remarks I made in the top level descriptions were marked as resolved where not addressed if I am not mistaken.
Co-Authored-By: Olivier Grisel <olivier.grisel@ensta.org>
|
My bad. |
ogrisel
left a comment
There was a problem hiding this comment.
Overall LGTM, just a few suggestions for additional fixes / improvements:
| try: | ||
| FileNotFoundError = FileNotFoundError | ||
| except NameError: # FileNotFoundError is Python 3-only | ||
| from loky.backend.semlock import FileNotFoundError |
There was a problem hiding this comment.
Nit: this could be simplified by always importing:
from loky.backend.semlock import FileNotFoundErrorThere was a problem hiding this comment.
I don't think so, because FileNotFoundError is not a global of loky.backend.semlock for Python 3, it is a item of the __builtins__. At least it does not work on my machine.
|
Can you try to merge master into this branch to check whether that can help codedoc? The report link is broken on this PR for some reason. |
|
Hum codecov is now green... Maybe that was just the PyPy report that was late. |
Co-Authored-By: Olivier Grisel <olivier.grisel@ensta.org>
Co-Authored-By: Olivier Grisel <olivier.grisel@ensta.org>
…rreglaser/loky into resource-tracker-refcounting
|
The pthread import needs to be protected on Windows: |
|
|
|
Merged! Thank you very much @pierreglaser. |
|
I forgot to ask you to document the new feature in the changelog. |
|
@pierreglaser we should now target 2.7.0 in the changelog because this is a new feature. |
This PR proposes to make
resource_trackerin charge of cleaning up shared resources between between Python processes AT RUNTIME (and not only during shutdown as it is currently done). It does so by reference counting objects each time a Python process demands it (e.g means a Python process sends a"REGISTER"/"UNREGISTER"request to theresource_tracker). If an object's refcount drops to 0, theresource_trackercleans it up. Previously, Python processes themselves would clean up the shared objects, and the resource_tracker would only intervene at the end of the program when all other processes connected to it have exited.This PR is principally motivated by joblib/joblib#806, that shows the need for a proper way to track shared memmaped files usage between processes, as well as clean them up as soon as possible (and not wait for the shutdown of the
joblibworker pool).