Skip to content

Add optimized versions of isdir / isfile on Windows #101196

Description

@mdboom

I went down this rabbit hole when someone mentioned that isfile/isdir/exists all make a rather expensive os.stat call on Windows (which is actually a long wrapper around a number of system calls on Windows), rather than the simpler and more direct call to GetFileAttributeW.

I noticed that at one point there was a version of isdir that does exactly this. At the time, this claimed a 2x speedup.

However, this C implementation of isdir was removed as part of a large set of changes in df2d4a6, and as a result, isdir got faster.

With the following benchmark:

isdir benchmark
import os.path
import timeit


for i in range(100):
    os.makedirs(f"exists{i}", exist_ok=True)


def test_exists():
    for i in range(100):
        os.path.isdir(f"exists{i}")


def test_extinct():
    for i in range(100):
        os.path.isdir(f"extinct{i}")


print(timeit.timeit(test_exists, number=100))
print(timeit.timeit(test_extinct, number=100))


for i in range(100):
    os.rmdir(f"exists{i}")

I get the following with df2d4a6:

exists: 0.18694799999957468
doesn't exist: 0.08418370000072173

and with the prior commit:

exists: 0.25393609999991895
doesn't exist: 0.08511730000009265

So, from this, I'd conclude that the idea of replacing calls to os.stat with calls to GetFileAttributeW would not bear fruit, but @zooba should probably confirm I'm benchmarking the right thing and making sense.

In any event, we should probably remove the little vestige that imports this fast path that was removed:

try:
    # The genericpath.isdir implementation uses os.stat and checks the mode
    # attribute to tell whether or not the path is a directory.
    # This is overkill on Windows - just pass the path to GetFileAttributes
    # and check the attribute from there.
    from nt import _isdir as isdir
except ImportError:
    # Use genericpath.isdir as imported above.
    pass

Linked PRs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions