首页 > 编程问答 >改进删除文件和目录的 python 脚本运行时间

改进删除文件和目录的 python 脚本运行时间

时间:2024-08-07 15:54:41浏览次数:17  
标签:python python-3.x performance runtime

我有一个 Python 脚本,可以删除 X 天之前的文件和目录。然而,该脚本运行在一个包含数百万个文件和目录的巨大目录上。按照目前的速度,完成删除过程大约需要六周时间(查看磁盘空间指标)。

看来主要瓶颈在于列出文件和目录。任何人都可以建议代码更改或优化,以帮助减少运行时间?

不确定它是否相关,但对于上下文来说,它在 k8s 中作为作业运行,因此资源不是问题。

def delete_files(root_directory, delete_time_threshold):
    global EXAMINED_FILES
    global DELETED_FILES
    try:
        for dirpath, dirnames, filenames in os.walk(root_directory):
            for file in filenames:
                file_path = os.path.join(dirpath, file)
                try:
                    file_mtime = os.path.getmtime(file_path)
                    EXAMINED_FILES += 1
                    if file_mtime < delete_time_threshold:
                        os.remove(file_path)
                        logging.debug(f"File {file} deleted because mtime {file_mtime} is older than threshold {delete_time_threshold}")
                        DELETED_FILES += 1
                except Exception as e:
                    logging.error(f"Error deleting file {file_path}")
    except Exception as e:
        logging.error(f"Error walking root directory {root_directory}: {e}")

def delete_empty_directories(root_directory, allowed_empty_dirs):
    global EXAMINED_DIRS
    global DELETED_DIRS
    global SKIPPED_DELETE_DIRS
    try:
        for dirpath, dirnames, filenames in os.walk(root_directory):
            if dirpath != root_directory: #don't look at the root directory
                EXAMINED_DIRS += 1
                try:
                    if not dirnames and not filenames:
                        relative_dirpath = re.sub(f'^{root_directory}/', '', dirpath)
                        if relative_dirpath and relative_dirpath in allowed_empty_dirs:
                            logging.debug(f"Skipping deletion of allowed empty directory: {dirpath}")
                            SKIPPED_DELETE_DIRS += 1
                        else:
                            os.rmdir(dirpath)
                            logging.debug(f"Deleted empty directory: {dirpath}")
                            DELETED_DIRS += 1
                except Exception as e:
                    logging.error(f"Error deleting directory {dirpath}")
    except Exception as e:
        logging.error(f"Error walking root directory {root_directory}: {e}")


谢谢!


当然,我可以帮助你优化你的 Python 脚本。在处理数百万个文件时,效率至关重要,而你的分析(瓶颈在于列出文件)很可能是准确的。

让我们探讨一下可以提高脚本性能的几种方法:

  1. 使用 os.scandir() 而不是 os.walk() os.walk() 对于大型目录来说可能很慢,因为它会生成所有文件名和目录名的完整列表,然后才会遍历它们。而 os.scandir() 返回一个迭代器,该迭代器按需生成目录条目。这可能会显着减少内存使用量并加快处理速度,尤其是在目录较深的情况下。

```python import os

def delete_files(root_directory, delete_time_threshold): for entry in os.scandir(root_directory): if entry.is_file(): file_path = entry.path try: file_mtime = entry.stat().st_mtime if file_mtime < delete_time_threshold: os.remove(file_path) logging.debug(f"已删除文件 {entry.name},因为修改时间 {file_mtime} 早于阈值 {delete_time_threshold}") except Exception as e: logging.error(f"删除文件 {file_path} 时出错") elif entry.is_dir(): delete_files(entry.path, delete_time_threshold) # 递归删除子目录中的文件 ```

  1. 并行处理: 由于你提到资源不是问题,因此可以考虑使用多处理来并行删除文件。Python 的 multiprocessing 模块可以帮助你实现这一点。你可以将目录拆分为多个块,并让多个进程同时处理这些块。

```python import os import multiprocessing

def delete_files_in_directory(directory, delete_time_threshold): for entry in os.scandir(directory): # ... [与之前的代码相同的删除逻辑]

def delete_files(root_directory, delete_time_threshold): with multiprocessing.Pool() as pool: for dirpath, dirnames, filenames in os.walk(root_directory): pool.apply_async(delete_files_in_directory, args=(dirpath, delete_time_threshold)) pool.close() pool.join() ```

  1. 删除空目录优化: 你的当前脚本在删除文件后会遍历所有目录。为了优化这一点,你可以在删除文件时跟踪空目录,然后仅尝试删除这些目录。

```python def delete_files(root_directory, delete_time_threshold): empty_dirs = set() # ... [使用 os.scandir() 删除文件的代码]

       elif entry.is_dir():
           delete_files(entry.path, delete_time_threshold)
           if not os.listdir(entry.path):  # 检查目录是否为空
               empty_dirs.add(entry.path)

   # 删除文件后删除空目录
   for dirpath in empty_dirs:
       try:
           os.rmdir(dirpath)
           logging.debug(f"已删除空目录:{dirpath}")
       except Exception as e:
           logging.error(f"删除目录 {dirpath} 时出错")

```

  1. 考虑使用 find 对于基于时间的文件删除, find 命令通常比使用纯 Python 更快。你可以使用 Python 的 subprocess 模块来调用 find

```python import subprocess

def delete_files(root_directory, days_old): subprocess.run(["find", root_directory, "-type", "f", "-mtime", f"+{days_old}", "-delete"]) ```

选择正确的方法:

  • 如果你的瓶颈确实是文件系统访问,那么 os.scandir() 、并行处理和空目录优化将会非常有益。
  • 如果你主要删除旧文件,那么使用 find 可能是最快的选择,因为它经过了此类任务的优化。

对性能进行基准测试: 对任何更改进行基准测试,以了解它们对你的特定用例的影响非常重要。每个环境都是独一无二的,并且一种方法可能比另一种方法表现得更好,具体取决于你的数据和系统。

请记住,在对生产系统进行任何更改之前,始终要备份数据并在测试环境中彻底测试你的代码。祝你好运,优化愉快!

标签:python,python-3.x,performance,runtime
From: 78842402

相关文章

  • python+flask计算机毕业设计新冠疫情后病历管理系统(程序+开题+论文)
    志羽·羽场管理与智能推荐系统2220o本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景新冠疫情的爆发对全球医疗体系产生了深远影响,特别是在病历管理方面。传统的病历管理方式在面对大规模......
  • python+flask计算机毕业设计微信小程序“班级小管家”(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的迅猛发展和移动互联网的普及,微信小程序作为一种轻量级的应用程序,凭借其无需下载、即用即走的特性,在教育领域展现出了巨大的......
  • 您好,我有一个关于仅使用 python 3.10 发送电子邮件附件的问题
    我在发送包含附件的电子邮件时遇到问题。我的电子邮件的内容类型似乎设置不正确,这导致附件无法正确附加。这是我的电子邮件发送功能的片段:python复制代码self.send(subject=self.subject、recipients=self.recipients、html=""、text=""、attachments=self.attac......
  • python+flask计算机毕业设计社区居民信息管理系统 (程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着城市化进程的加快,社区居民信息管理成为社区管理的重要组成部分。传统的社区管理方式存在信息更新不及时、管理效率低下等问题,难以满足......
  • Python安装教程(含MacOS&&Linux系统)
    Python安装教程Windows用户访问Python官网:WelcometoPython.org 打开下载好的安装包根据提示安装   Pip换源(系统级别)(注:Pip在3.4以上的版本才支持,3.4之前的版本可以在cmd中输入 easy_installpip 下载pip)1.为什么要换源?Python安装......
  • python
    字符串比较按位比较,有一位大,整体就大。函数多返回值正确:deftest_return():return1,2,3错误:return1return2函数的多种传参方式位置参数:关键字参数:函数调用时通过“键=值”的形式传递参数(传参顺序无所谓)eg:test(name="niu",age="19")缺省参数:举例说明:def......
  • 将普通 python 文件导入另一个文件时出现 AttributeError
    我是新手。我正在尝试将简单的python文件导入到我的主文件中。相同的代码在我的mac上工作,但在我的电脑上不起作用。我不断收到此错误消息。“AttributeError:模块‘logo’没有属性‘hammer_logo’”第一个文件拍卖.py代码importlogoprint(logo.hammer_logo)第......
  • 使用python读取mysql数据,并记录到本地的文件中
    上次写过一次读取sqlserver数据,写入本地文件。今天分享一下mysql的。原理相似,希望对大家有小小的帮忙PS,我是3.6.13版本python,上一版本用包mysql-connector,一直不成功,查询官方文档,发现这个版本的PYTHON简直是奇葩的存在了。基本所有版本都支持,就是几个小版本排除在外了。......
  • python合并音视频-通过moviepy模块合并音视频
    ......
  • esp32安装circuitpython
    安装Thonnyhttps://thonny.org/在Thonny中安装circuitpython在配置解释器中选择circuitython然后点击右下角“安装或更新...“variant这里我选择了DOITesp32DevelopmentBoard(试过其他的一些个,不知道为什么安装完之后会无限重启,所以最后选择了这个)烧录完之后,重新连接,Th......