为什么shutil.rmtree()这么慢?

时间:2011-03-29 10:14:40

标签: python rm

我去检查如何删除Python中的目录,并导致使用shutil.rmtree()。与我对rm --recursive的期望相比,这让我感到惊讶。是否有更快的替代品,缺少使用subprocess模块?

3 个答案:

答案 0 :(得分:7)

The implementation做了很多额外的处理:

def rmtree(path, ignore_errors=False, onerror=None):
    """Recursively delete a directory tree.

    If ignore_errors is set, errors are ignored; otherwise, if onerror
    is set, it is called to handle the error with arguments (func,
    path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
    path is the argument to that function that caused it to fail; and
    exc_info is a tuple returned by sys.exc_info(). If ignore_errors
    is false and onerror is None, an exception is raised.

    """
    if ignore_errors:
         def onerror(*args):
              pass
    elif onerror is None:
         def onerror(*args):
              raise
    try:
         if os.path.islink(path):
              # symlinks to directories are forbidden, see bug #1669
              raise OSError("Cannot call rmtree on a symbolic link")
    except OSError:
         onerror(os.path.islink, path, sys.exc_info())
         # can't continue even if onerror hook returns
         return
    names = []
    try:
         names = os.listdir(path)
    except os.error, err:
         onerror(os.listdir, path, sys.exc_info())
    for name in names:
         fullname = os.path.join(path, name)
         try:
              mode = os.lstat(fullname).st_mode
         except os.error:
              mode = 0
         if stat.S_ISDIR(mode):
              rmtree(fullname, ignore_errors, onerror)
         else:
             try:
                 os.remove(fullname)
             except os.error, err:
                 onerror(os.remove, fullname, sys.exc_info())
    try:
         os.rmdir(path)
    except os.error:
         onerror(os.rmdir, path, sys.exc_info()) 

注意用于创建新文件名的os.path.join();字符串操作需要时间。而rm(1)实现使用unlinkat(2)系统调用,它不执行任何其他字符串操作。 (事实上​​,保存内核不会遍历整个namei()只是为了找到公共目录,一遍又一遍。内核的dentry缓存很好用,但仍然可以是一个相当数量的内核字符串操作和比较。)rm(1)实用程序绕过所有字符串操作,只需使用目录的文件描述符。

此外,rm(1)rmtree()都会检查树中每个文件和目录的st_mode;但是C实现不需要将每个struct statbuf转换为Python对象,只是为了执行简单的整数掩码操作。我不知道这个过程花了多长时间,但它对目录树中的每个文件,目录,管道,符号链接等都会发生一次。

答案 1 :(得分:1)

如果你关心速度:

os.system('rm -fr“%s”'%your_dirname)

除此之外我没有找到shutil.rmtree()慢得多......当然,所涉及的Python级别还有额外的开销。除此之外,如果你提供合理的数字,我只相信这样的主张。

答案 2 :(得分:1)

虽然我不知道出了什么问题,但您可以尝试其他方法,例如删除所有文件,然后尝试目录

for r,d,f in os.walk("path"):
   for files in f:
       os.remove ( os.path.join(r,files) )
   os.removedirs( r )