You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
assignee='https://github.com/serhiy-storchaka'closed_at=<Date2016-09-07.11:18:35.524>created_at=<Date2016-01-06.22:55:27.013>labels= ['library', 'performance']
title='Use scandir() to speed up pathlib globbing'updated_at=<Date2021-05-14.08:09:53.071>user='https://github.com/gvanrossum'
The globbing functionality in pathlib (Path.glob() and Path.rglob()) might benefit from using the new optimized os.scandir() interface. It currently just uses os.listdir(). The Path.iterdir() method might also benefit (though less so).
There's also a sideways connection with http://bugs.python.org/issue26031 (adding an optional stat cache) -- the cache could possibly keep the DirEntry objects and use their (hopefully cached) attributes. This is more speculative though (and what if the platform's DirEntry doesn't cache?)
As I recall, if the platform's DirEntry doesn't provide the cacheable attributes when first called, those attributes will be looked up (and cached) on first access.
As I recall, if the platform's DirEntry doesn't provide the cacheable attributes when first called, those attributes will be looked up (and cached) on first access.
scandir() is not magic. It simply provides info given by the OS: see readdir() on UNIX and FindFirstFile()/FindNextFile() on Windows.
DirEntry calls os.stat() if needed, but it caches the result.
The DirEntry docs say for most methods "In most cases, no system call is
required" which is pretty non-committal. :-( The only firm promise is for
inode(), which is pretty useless.
benhoyt commented on Jan 7, 2016
benhoytmannequin
Mannequin
More actions
Guido, it's true that in almost all cases you get the speedup (no system call), and it's very much worth using. But the idea with the docs being non-committal is because being specific would make the docs fairly complex. I believe it's as follows for is_file/is_dir/is_symlink:
no system call required on Windows or Unix if the entry is not a symlink
unless you're on Unix with some different file system (maybe a network FS?) where d_type is DT_UNKNOWN
some other edge case which I've probably forgotten :-)
Do you think the docs should try to make this more specific?
Ben, I think it's worth calling out what the rules are around symlinks. I'm
guessing the info that is initially present is a subset of lstat(), so if
that indicates it's a symlink, is_dir() and is_file() will need a stat()
call, *unless* follow_symlinks is False.
Another question: for symlinks, there are two different possible stat
results: one for stat() and one for lstat(). Are these both cached
separately? Or is only one of them? (Experimentally, they are either both
cached or the cache remembers the follow_symlinks flag and re-fetches the
other result.)
Related, "this method always requires a system call", that remark seems to
disregard the cache.
I'd be happy to review a doc update patch if you make one.
Guido, I've made some tweaks and improvements to the DirEntry docs here: http://bugs.python.org/issue26248 -- the idea is to fix the issues you mentioned to clarify when system calls are required with symlinks, mentioning that the results are cached separately for follow_symlinks True and False, etc.
Activity
gvanrossum commentedon Jan 6, 2016
The globbing functionality in pathlib (Path.glob() and Path.rglob()) might benefit from using the new optimized os.scandir() interface. It currently just uses os.listdir(). The Path.iterdir() method might also benefit (though less so).
There's also a sideways connection with http://bugs.python.org/issue26031 (adding an optional stat cache) -- the cache could possibly keep the DirEntry objects and use their (hopefully cached) attributes. This is more speculative though (and what if the platform's DirEntry doesn't cache?)
vstinner commentedon Jan 6, 2016
Related issue: issue bpo-25596 "regular files handled as directories in the glob module".
ethanfurman commentedon Jan 6, 2016
As I recall, if the platform's DirEntry doesn't provide the cacheable attributes when first called, those attributes will be looked up (and cached) on first access.
vstinner commentedon Jan 6, 2016
scandir() is not magic. It simply provides info given by the OS: see readdir() on UNIX and FindFirstFile()/FindNextFile() on Windows.
DirEntry calls os.stat() if needed, but it caches the result.
DirEntry doc tries to explain when syscalls or required or not, depending on the requested information and the platform:
https://docs.python.org/dev/library/os.html#os.DirEntry
gvanrossum commentedon Jan 6, 2016
The DirEntry docs say for most methods "In most cases, no system call is
required" which is pretty non-committal. :-( The only firm promise is for
inode(), which is pretty useless.
benhoyt commentedon Jan 7, 2016
Guido, it's true that in almost all cases you get the speedup (no system call), and it's very much worth using. But the idea with the docs being non-committal is because being specific would make the docs fairly complex. I believe it's as follows for is_file/is_dir/is_symlink:
Do you think the docs should try to make this more specific?
gvanrossum commentedon Jan 7, 2016
Ben, I think it's worth calling out what the rules are around symlinks. I'm
guessing the info that is initially present is a subset of lstat(), so if
that indicates it's a symlink, is_dir() and is_file() will need a stat()
call, *unless* follow_symlinks is False.
Another question: for symlinks, there are two different possible stat
results: one for stat() and one for lstat(). Are these both cached
separately? Or is only one of them? (Experimentally, they are either both
cached or the cache remembers the follow_symlinks flag and re-fetches the
other result.)
Related, "this method always requires a system call", that remark seems to
disregard the cache.
I'd be happy to review a doc update patch if you make one.
vstinner commentedon Jan 7, 2016
"Another question: for symlinks, there are two different possible stat
results: one for stat() and one for lstat(). Are these both cached
separately?"
Hopefully, both are cached. It's directly the result of stat() and
stat(follow_symlinks=False) which are cached (so a os.stat_result
object).
serhiy-storchaka commentedon Jan 11, 2016
Proposed minimal patch implements globbing in pathlib using os.scandir(). Here are results of microbenchmarks:
See msg257954 in bpo-25596 for comparison with the glob module.
benhoyt commentedon Jan 31, 2016
Guido, I've made some tweaks and improvements to the DirEntry docs here: http://bugs.python.org/issue26248 -- the idea is to fix the issues you mentioned to clarify when system calls are required with symlinks, mentioning that the results are cached separately for follow_symlinks True and False, etc.
python-dev commentedon Sep 7, 2016
New changeset 927665c4aaab by Serhiy Storchaka in branch 'default':
Issue bpo-26032: Optimized globbing in pathlib by using os.scandir(); it is now
https://hg.python.org/cpython/rev/927665c4aaab