首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >复制文件的x64位性能评估/问题

复制文件的x64位性能评估/问题
EN

Stack Overflow用户
提问于 2010-11-25 16:41:11
回答 4查看 1.5K关注 0票数 5

在编写一种备份应用程序时,我对Windows上的文件复制性能进行了评估。

我有几个问题,不知道你的意见。

谢谢!

卢卡斯。

问题:

  1. 为什么在复制10 GiB文件时性能比1 GiB文件慢得多?
  2. 为什么shutil.copyfile这么慢?
  3. 为什么win32file.CopyFileEx这么慢?这可能是因为旗标win32file.COPY_FILE_RESTARTABLE吗?然而,它不接受int 1000作为标志(COPY_FILE_NO_BUFFERING),这是对大型文件的推荐:http://msdn.microsoft.com/en-us/library/aa363852%28VS.85%29.aspx
  4. Using空ProgressRoutine似乎对不使用ProgressRoutine没有任何影响。
  5. 有一个替代的、性能更好的复制文件的方法吗?

结果为1 GiB和10 GiB文件:

代码语言:javascript
复制
test_file_size             1082.1 MiB    10216.7 MiB

METHOD                      SPEED           SPEED
robocopy.exe                111.0 MiB/s     75.4 MiB/s
cmd.exe /c copy              95.5 MiB/s     60.5 MiB/s
shutil.copyfile              51.0 MiB/s     29.4 MiB/s
win32api.CopyFile           104.8 MiB/s     74.2 MiB/s
win32file.CopyFile          108.2 MiB/s     73.4 MiB/s
win32file.CopyFileEx A       14.0 MiB/s     13.8 MiB/s
win32file.CopyFileEx B       14.6 MiB/s     14.9 MiB/s

测试环境:

代码语言:javascript
复制
Python:
ActivePython 2.7.0.2 (ActiveState Software Inc.) based on
Python 2.7 (r27:82500, Aug 23 2010, 17:17:51) [MSC v.1500 64 bit (AMD64)] on win32

source = mounted network drive
source_os = Windows Server 2008 x64

destination = local drive
destination_os = Windows Server 2008 R2 x64

备注:

代码语言:javascript
复制
'robocopy.exe' and 'cmd.exe /c copy' were run using subprocess.call()

win32file.CopyFileEx A(不使用ProgressRoutine):

代码语言:javascript
复制
def Win32_CopyFileEx_NoProgress( ExistingFileName, NewFileName):
    win32file.CopyFileEx(
        ExistingFileName,                             # PyUNICODE           | File to be copied
        NewFileName,                                  # PyUNICODE           | Place to which it will be copied
        None,                                         # CopyProgressRoutine | A python function that receives progress updates, can be None
        Data = None,                                  # object              | An arbitrary object to be passed to the callback function
        Cancel = False,                               # boolean             | Pass True to cancel a restartable copy that was previously interrupted
        CopyFlags = win32file.COPY_FILE_RESTARTABLE,  # int                 | Combination of COPY_FILE_* flags
        Transaction = None                            # PyHANDLE            | Handle to a transaction as returned by win32transaction::CreateTransaction
        )

win32file.CopyFileEx B(使用空ProgressRoutine):

代码语言:javascript
复制
def Win32_CopyFileEx( ExistingFileName, NewFileName):
    win32file.CopyFileEx(
        ExistingFileName,                             # PyUNICODE           | File to be copied
        NewFileName,                                  # PyUNICODE           | Place to which it will be copied
        Win32_CopyFileEx_ProgressRoutine,             # CopyProgressRoutine | A python function that receives progress updates, can be None
        Data = None,                                  # object              | An arbitrary object to be passed to the callback function
        Cancel = False,                               # boolean             | Pass True to cancel a restartable copy that was previously interrupted
        CopyFlags = win32file.COPY_FILE_RESTARTABLE,  # int                 | Combination of COPY_FILE_* flags
        Transaction = None                            # PyHANDLE            | Handle to a transaction as returned by win32transaction::CreateTransaction
        )

def Win32_CopyFileEx_ProgressRoutine(
    TotalFileSize,
    TotalBytesTransferred,
    StreamSize,
    StreamBytesTransferred,
    StreamNumber,
    CallbackReason,                         # CALLBACK_CHUNK_FINISHED or CALLBACK_STREAM_SWITCH
    SourceFile,
    DestinationFile,
    Data):                                  # Description
    return win32file.PROGRESS_CONTINUE      # return of any win32file.PROGRESS_* constant
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-12-08 16:52:27

问题3:

您误解了Microsofts中的COPY_FILE_NO_BUFFERING标志。它不是int 1000,而是十六进制1000 (0x1000 => int值: 4096)。当您设置CopyFlags = 4096时,您将得到(?)Windows环境中最快的复制例程。我在我的数据备份代码中使用相同的例程,它非常快,每天传输兆字节大小的数据。

问题4:

这不重要,因为这是一个回调。但是总的来说,你不应该在里面放太多的代码,保持它的整洁和流畅。

问题5:

根据我的经验,它是标准Windows环境中最快的复制例程。可能会有更快的自定义复制例程,但是当使用普通的Windows时,没有比这更好的了。

票数 3
EN

Stack Overflow用户

发布于 2010-11-25 17:00:58

很有可能,因为你测量的完成时间不同。

我猜一个1Gb的文件可以很舒服地放入ram中。因此,操作系统可能只是缓存它,并告诉您的应用程序在内核缓冲区中大部分(可能全部)仍未刷新时,它已被复制。

但是,10G文件不适合ram,所以它必须在完成之前编写(大部分)它。

如果你想要一个有意义的测量,

( a)每次运行之前清除文件系统缓冲区缓存--如果您的操作系统没有提供一种方便的方法,请重新启动(NB: Windows没有提供方便的方法,我认为有一个系统内部工具可以做到这一点)。在网络文件系统的情况下,也清除服务器上的缓存。

b)在测量完成时间之前,在完成后将文件同步到磁盘

那么我希望你能看到更多一致的时间。

票数 3
EN

Stack Overflow用户

发布于 2013-04-05 11:34:50

回答你的问题2:

shutil.copyfile()太慢了,因为默认情况下它使用一个16 K的副本缓冲区。最后,它在shutil.copyfileobj()中结束,它看起来如下所示:

代码语言:javascript
复制
def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    while 1:
        buf = fsrc.read(length)
        if not buf:
            break
        fdst.write(buf)

在你的例子中,它是在读16K和写16K之间的乒乓声。如果要在GB文件上直接使用copyfileobj(),但是使用128 GB的缓冲区,您将看到性能大大提高。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4279207

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档