Skip to content

GH-113225: Speed up pathlib.Path.glob()#113226

Merged
barneygale merged 6 commits into
python:mainfrom
barneygale:gh-113225
Jan 4, 2024
Merged

GH-113225: Speed up pathlib.Path.glob()#113226
barneygale merged 6 commits into
python:mainfrom
barneygale:gh-113225

Conversation

@barneygale

@barneygale barneygale commented Dec 17, 2023

Copy link
Copy Markdown
Contributor

Use os.DirEntry.path as the string representation of child paths.

Corner case: when we os.scandir('.'), the path atttribute will resemble './foo', which isn't normalized by pathlib standards. In this case we use the entry name, which looks like 'foo'.

Use `os.DirEntry.path` as the string representation of child paths, unless
the parent path is empty, in which case we use the entry `name`.
@barneygale

barneygale commented Dec 17, 2023

Copy link
Copy Markdown
Contributor Author

Up to 15% faster in some simple tests:

$ ./python -m timeit -s "from pathlib import Path" "list(Path().glob('**/*', follow_symlinks=True))"
5 loops, best of 5: 78.8 msec per loop  # before
5 loops, best of 5: 67.9 msec per loop  # after
# --> 1.16x faster

$ ./python -m timeit -s "from pathlib import Path" "list(Path.cwd().glob('**/*', follow_symlinks=True))"
5 loops, best of 5: 79.6 msec per loop  # before
5 loops, best of 5: 70.5 msec per loop  # after
# --> 1.13x faster

edit: patch revised; test cases for iterdir() removed.

Comment thread Lib/pathlib/__init__.py Outdated
@serhiy-storchaka

Copy link
Copy Markdown
Member

How does it work for [p.name for p in Path.cwd().iterdir()]?

@barneygale

Copy link
Copy Markdown
Contributor Author

How does it work for [p.name for p in Path.cwd().iterdir()]?

Same result but much slower (!), as the .name attribute triggers path parsing:

$ ./python -m timeit -s "from pathlib import Path" "[p.name for p in Path.cwd().iterdir()]"
2000 loops, best of 5: 139 usec per loop  # before
1000 loops, best of 5: 371 usec per loop  # after

Will fix! Thanks.

@barneygale barneygale changed the title GH-113225: Speed up pathlib.Path.iterdir() and glob() GH-113225: Speed up pathlib.Path.glob() Dec 18, 2023
@barneygale

Copy link
Copy Markdown
Contributor Author

I've undone the change to iterdir() as it's hard to predict usage patterns.

With glob() the goal is to maintain a normalized string path as cheaply as possible. The string path is passed to scandir() and matched against a regex when expanding ** patterns.

@barneygale

Copy link
Copy Markdown
Contributor Author

I've merged the ABC-specific changes separately (#113556) so this PR should be pretty laser-focused now :D

@barneygale

Copy link
Copy Markdown
Contributor Author

Patch further revised so that we continue to set _drv, _root and _tail_cached as before, which might be important for some users. The speedup is reduced to about 3-5%:

$ ./python -m timeit -s "from pathlib import Path" "list(Path().glob('**/*', follow_symlinks=True))"
5 loops, best of 5: 84.3 msec per loop  # before
5 loops, best of 5: 80.1 msec per loop  # after

$ ./python -m timeit -s "from pathlib import Path" "list(Path.cwd().glob('**/*', follow_symlinks=True))"
5 loops, best of 5: 84.4 msec per loop  # before
5 loops, best of 5: 82   msec per loop  # after

@barneygale
barneygale enabled auto-merge (squash) January 4, 2024 20:38
@barneygale
barneygale merged commit c2e8298 into python:main Jan 4, 2024
kulikjak pushed a commit to kulikjak/cpython that referenced this pull request Jan 22, 2024
Use `os.DirEntry.path` as the string representation of child paths, unless
the parent path is empty, in which case we use the entry `name`.
aisk pushed a commit to aisk/cpython that referenced this pull request Feb 11, 2024
Use `os.DirEntry.path` as the string representation of child paths, unless
the parent path is empty, in which case we use the entry `name`.
Glyphack pushed a commit to Glyphack/cpython that referenced this pull request Sep 2, 2024
Use `os.DirEntry.path` as the string representation of child paths, unless
the parent path is empty, in which case we use the entry `name`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Performance or resource usage topic-pathlib

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants