GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GH-115060: Speed up `pathlib.Path.glob()` by skipping directory scanning by barneygale · Pull Request #116152 · python/cpython

Conversation

@barneygale

@barneygale barneygale commented Feb 29, 2024 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

For ordinary literal pattern segments (e.g. foo/bar in foo/bar/../**), skip calling scandir() on each segment, and instead call exists() or is_dir() as necessary to exclude missing paths. This only applies when case_sensitive is None (the default); otherwise we can't guarantee case sensitivity or realness with this approach. If follow_symlinks is False we also need to exclude symlinks from intermediate segments.

This restores an optimization that was removed in da1980a by some eejit. It's actually even faster because we don't stat() intermediate directories, and in some cases we can skip all filesystem access when expanding a literal part (e.g. when it's followed by a non-recursive wildcard segment).

  • Issue: Speed up pathlib.Path.glob() by removing redundant regex matching #115060

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@barneygale
pythonGH-115060: Speed up pathlib.Path.glob() by skipping directory…
f1b5603
… scanning.

For ordinary literal pattern segments (e.g. `foo/bar` in `foo/bar/../**`),
skip calling `_scandir()` on each segment, and instead call `exists()` or
`is_dir()` as necessary to exclude missing paths. This only applies when
*case_sensitive* is `None` (the default); otherwise we can't guarantee case
sensitivity or realness with this approach. If *follow_symlinks* is `False`
we also need to exclude symlinks from intermediate segments.

This restores an optimization that was removed in da1980a by some eejit.
It's actually even faster because we don't `stat()` intermediate
directories, and in some cases we can skip all filesystem access when
expanding a literal part (e.g. when it's followed by a non-recursive
wildcard segment).
@barneygale barneygale added performance Performance or resource usage topic-pathlib labels Feb 29, 2024
@barneygale
barneygale requested a review from zooba February 29, 2024 20:57
@bedevere-app bedevere-app Bot added the awaiting core review label Feb 29, 2024
@bedevere-app bedevere-app Bot mentioned this pull request Feb 29, 2024
Speed up pathlib.Path.glob() by removing redundant regex matching #115060
Closed
@barneygale

barneygale commented Feb 29, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

Quite a lot faster:

$ ./python -m timeit -s "from pathlib import Path" "list(Path().glob('Lib/pathlib/__init__.py'))"
 2000 loops, best of 5: 195 usec per loop  # before
20000 loops, best of 5:  17 usec per loop  # after
$ ./python -m timeit -s "from pathlib import Path" "list(Path().glob('Lib/pathlib/*'))"
 2000 loops, best of 5: 197   usec per loop  # before
10000 loops, best of 5:  28.8 usec per loop  # after
$ ./python -m timeit -s "from pathlib import Path" "list(Path().glob('Lib/*/__init__.py'))"
 200 loops, best of 5:   1.24 msec per loop  # before
1000 loops, best of 5: 307    usec per loop  # after
$ ./python -m timeit -s "from pathlib import Path" "list(Path().glob('*/pathlib/__init__.py'))"
 200 loops, best of 5:   1.22 msec per loop  # before
1000 loops, best of 5: 261    usec per loop  # after
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

barneygale added 5 commits February 29, 2024 21:09
@barneygale
Also skip initial is_dir()
cbc7002
@barneygale
Fix tests
d1f8cae
@barneygale
Fix tests, attempt 2
80e384c
@barneygale
Fix handling of final literal symlink
0b98008
@barneygale
Make follow_symlinks behaviour a bit clearer
dfc4766
@barneygale
barneygale marked this pull request as draft March 4, 2024 18:19
@bedevere-app bedevere-app Bot removed the awaiting core review label Mar 4, 2024
@barneygale barneygale closed this Apr 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@zooba zooba Awaiting requested review from zooba

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

performance Performance or resource usage topic-pathlib

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@barneygale
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.