【问题标题】:Forcing os.walk to stop if taking too long time如果花费太长时间,则强制 os.walk 停止
【发布时间】:2017-03-03 00:56:43
【问题描述】:

我想在具有给定文件扩展名的目录树中查找所有文件。但是,有些文件夹非常大,因此如果需要很长时间(比如 1 秒),我想停止这个过程。我当前的代码如下所示:

import os
import time

start_time = time.time()
file_ext = '.txt'
path = 'C:/'
file_list = []
for root, dirs, files in os.walk(path):
    for file in files:
        if file.endswith(file_ext):
            relDir = os.path.relpath(root, path)
            relFile = os.path.join(relDir, file)
            file_list.append(relFile)
        if time.time() - start_time> 1:
            break
    if time.time() - start_time> 1:
        break

这段代码的问题在于,当我到达一个非常大的子文件夹时,在该文件夹被完全遍历之前,这段代码不会中断。如果该文件夹包含许多文件,则可能需要比我想要的更长的时间。有什么方法可以确保代码的运行时间不会超过分配的时间?

编辑:请注意,虽然找到加速代码的方法(例如通过使用 os.scandir)肯定会有所帮助,但这个问题主要涉及如何杀死正在运行的进程。

【问题讨论】:

  • 把它放在一个函数中并使用 return ?
  • 不幸的是,这会产生相同的结果。
  • 您的缩进很可能是错误的...尝试将您的问题复制粘贴回您的编辑器,看看它是否有效
  • 刚刚测试了您发布的代码,它总是在 1 秒后几乎立即退出 (1.00009) ...
  • @JoranBeasley 我认为问题在于 os.walk 在完全读取目录之前不会为您提供文件列表,因此在枚举文件时检查时间没有好处。

标签: python


【解决方案1】:

您可以在子进程中执行遍历并将其杀死。选项包括multiprocessing.Process,但 Windows 上的多处理库可能需要完成大量您不需要的工作。相反,您可以将 walker 代码通过管道传输到 python 子进程中并从那里开始。

import os
import sys
import threading
import subprocess as subp

walker_script = """
import os
import sys
path = os.environ['TESTPATH']
file_ext = os.environ['TESTFILEEXT']

# let parent know we are going
print('started')

for root, dirs, files in os.walk(path):
    for file in files:
        if file.endswith(file_ext):
            relDir = os.path.relpath(root, path)
            relFile = os.path.join(relDir, file)
            print(relFile)
"""

file_ext = '.txt'
path = 'C:/'

encoding = sys.getdefaultencoding()

# subprocess reads directories... additional python flags seek to
# speed python initialization. If a linuxy system, forking would
# be a good option.

env = {'TESTPATH':path, 'TESTFILEEXT':file_ext}
env.update(os.environ)
proc = subp.Popen([sys.executable, '-E', '-s', '-S', '-'], stdin=subp.PIPE,
    stdout=subp.PIPE,      # , stderr=open(os.devnull, 'wb'))
    env = env)

# write walker script
proc.stdin.write(walker_script.encode('utf-8'))
proc.stdin.close()

# wait for start marker
next(proc.stdout)

# timer kills directory traversal when bored
threading.Timer(1, proc.kill).start()

file_list = [line.decode(encoding).strip() for line in proc.stdout]
print(file_list)

【讨论】:

  • 使用上面的代码会给我错误Fatal Python error: Failed to initialize Windows random API (CryptoGen)。我对使用子进程不是很熟悉,所以我不太确定如何解释错误。感谢您的建议,我将不得不深入研究如何使用子流程。
  • @matnor - 我在调整孩子的处理环境时有点过于激进了。我更新了代码以克隆父级的环境。如果仍然有问题,可以删除 -E -s -S 标志,它们只是为了加快 python 加载时间。
  • 谢谢,代码现在运行。不幸的是,脚本在一秒钟后没有被杀死,而是继续运行。
猜你喜欢
  • 2014-07-29
  • 1970-01-01
  • 2015-11-28
  • 1970-01-01
  • 2015-03-21
  • 2019-03-16
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
相关资源
最近更新 更多