gpt4 book ai didi

python - 自己编写的 os.walk-alike 比 os.walk 本身慢得多 - 为什么?

转载 作者:行者123 更新时间:2023-11-28 22:12:56 28 4
gpt4 key购买 nike

不幸的是,这段代码比“os.walk”运行得慢,但为什么呢?

会不会是“for”循环导致运行缓慢?

“像‘os.walk’一样工作的代码:(“os.walk”函数做它做的事)

注意:我写作是为了提升自己!:

import os, time
from os.path import *

x = ""
y = []
z = []
var = 0

def walk(xew):
global top, var, x,y,z
if not var: var = [xew]
for i in var:
try:
for ii in os.listdir(i):
y.append(ii) if isdir(i+os.sep+ii) else z.append(ii)

x = top = i
var = [top+os.sep+i for i in os.listdir(top) if isdir(top+os.sep+i)]
except:
continue
yield x,y,z
yield from walk(var)
var.clear();y.clear();z.clear()

例如:

2 秒后结束:

for x,y,z in walk(path):
print(x)

在 0.5 秒内:

for x,y,z in os.walk(path):
print(x)

最佳答案

os.walk() 不使用 os.listdir()。它使用更快的 os.scandir() function ,它为每个目录条目提供了一个包含更多信息的迭代器:

Using scandir() instead of listdir() can significantly increase the performance of code that also needs file type or file attribute information, because os.DirEntry objects expose this information if the operating system provides it when scanning a directory. All os.DirEntry methods may perform a system call, but is_dir() and is_file() usually only require a system call for symbolic links; os.DirEntry.stat() always requires a system call on Unix but only requires one for symbolic links on Windows.

os.walk() 代码大量使用了 DirEntry.is_dir() 调用,它与 os.scandir()比使用 os.isdir()(必须进行单独的 os.stat() 调用)便宜得多。

接下来,您的代码过于频繁地调用 os.isdir()。您实际上是在为路径中的每个文件条目调用它两次。您已经收集了y 中的所有子目录,重新创建var 时无需再次测试路径。这些额外的 isdir() 调用会花费您很多时间。

var(没有进一步的子目录)时,您也会递归,导致您首先将空列表包装在另一个列表中,然后是 os.listdir () 抛出一个 TypeError 异常,你的毯子 Pokemon-catch-em-all 除了处理程序沉默。

接下来,您应该摆脱全局变量,并使用适当的变量名。 filesdirs 的名称要比 yz 清晰得多。因为您制作了 yz 全局变量,所以您保留了给定级别的所有文件和目录名称,并且对于向下的每个第一个子目录,您然后重新报告这些相同的文件和目录名称,就好像它们是这些子目录的成员一样。仅当到达此类目录树的第一个叶子(没有进一步的子目录)时,才会对 yz 调用 .clear()被执行,导致带有重复文件名的非常困惑的结果。

可以研究os.walk() source code ,但如果我们将其简化为仅使用自顶向下遍历且不进行错误处理,则归结为:

def walk(top):
dirs = []
nondirs = []

with os.scandir(top) as scandir_it:
for entry in scandir_it:
if entry.is_dir():
dirs.append(entry.name)
else:
nondirs.append(entry.name)

yield top, dirs, nondirs

for dirname in dirs:
new_path = os.path.join(top, dirname)
yield from walk(new_path)

请注意,没有使用全局变量;在这个算法中根本不需要任何东西。每个目录只有一个 os.scandir() 调用,dirs 变量被重新用于递归到子目录。

关于python - 自己编写的 os.walk-alike 比 os.walk 本身慢得多 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54402246/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com