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
shutil.copyfile should internally use os.sendfile when possible #69343
Comments
This is related to bpo-25063 (https://bugs.python.org/issue25063). Trying to use sendfile internally in shutil.copyfileobj was considered risky because of special Python files that expose a file descriptor but wrap it to add special behavior (eg: GzipFile). I believe such risk does not exist for shutil.copyfile, and it would be possible to use sendfile if available. |
Additional advantage of calling sendfile from shutil.copyfile: other fonctions in shutil module would automatically benefit from the use of senfile because they call copyfile directly (copy, copy2) or indirectly (copytree). So for example, the performance of shutil.copytree should be improved for free for directory trees containing big files. |
Thoughts anyone? My tests show a 30-40% performance improvement for 128KB-512MB single file copy: 128 KB file copy: $ dd if=/dev/urandom of=/tmp/f1 bs=1K count=128 Without the patch: With the patch: -------- $ dd if=/dev/urandom of=/tmp/f1 bs=1M count=8 Without the patch: With the patch: -------- $ dd if=/dev/urandom of=/tmp/f1 bs=1M count=512 Without the patch: With the patch: |
Adding interested parties from earlier ticket. |
I’ve never used sendfile() nor shutil.copyfile(), but my immediate reaction is maybe we need a backup plan if os.sendfile() is available but not supported in the circumstances. E.g. if it is practical to use copyfile() to copy from a named socket in the filesystem, the Linux man page <http://man7.org/linux/man-pages/man2/sendfile.2.html\> says it will raise EINVAL in this case. Maybe a test case would be good to prove this is still handled. |
Also, the os.sendfile() doc suggests that some platforms only support writing to sockets, so I definitely think a backup plan is needed. |
Thanks for the comment.
You are right, the man page clearly says:
I will improve the code and add tests for conditions where sendfile fails. I have tested it manually, but I will also add a test with a copy of a file > 4GB (it causes several calls to sendfile). |
I played a bit with Unix domain sockets, and it appears you can not open them like a file with open(). |
Here is an improved patch with the following changes:
|
I left a few comments. But it might be good if someone more familiar with the APIs could review this. Have you seen the socket.sendfile() implementation? It’s a bit of a mess, and the circumstances are slightly different, but it may offer partial inspiration. It seems a shame to have two separate high-level sendfile() wrappers, but I guess the use cases are just a little too far apart to be worth sharing much code. For the test case, it may be worth skipping the test if you run out of disk space. Similar to test_mmap and test_largefile. |
Also, man pages for Free BSD and OS X (where writing to a disk file is not supported) say it raises:
It is not clear what the priority of these errors is, so it might be safest to catch them all. But I wouldn’t catch any arbitrary OSError, because you may end up doing weird double copying or something for an out-of-space error. |
I'm not at all sure this is worth the maintenance burden at this point in time. So let's say I'm -0.5. I agree that a review and opinion by someone more familiar with the API would be best. I'm adding gps as nosy since this feels like the kind of performance improvement he might find interesting, so if he thinks it is worth it I'll change my vote :) |
Here is an updated patch that takes into account Martin's suggestions, both here and in the code review. |
Ping A small patch, but a good performance improvement :) |
Here is a new patch, with changes suggested by SilentGhost and josh.rosenberg in the review. |
Thank you SilentGhost for the second review on the v4 patch. Attached is the v5 patch which hopefully is getting even better. |
No further comments from me. I haven't run the test, but I trust it passes without any warnings. |
Can this patch be merged, or is there something I can do to improve it? |
If anyone is interested, I have created a package to monkey patch shutil.copyfile to benefit from sendfile, similarly to the last patch, but it also works on older Python versions down to 2.7. PyPI link: https://pypi.python.org/pypi/pyfastcopy/ |
Different implementation: bpo-33639. |
Closing as duplicate of bpo-33671. |
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: