سؤال

عند برمجة نوع من تطبيق النسخ الاحتياطي ، قمت بتقييم لأداء نسخ الملفات على Windows.

لدي العديد من الأسئلة وأتساءل عن آرائك.

شكرًا لك!

لوكاس.

أسئلة:

  1. لماذا يكون الأداء أبطأ بكثير عند نسخ ملف GIB 10 مقارنة بملف GIB 1؟

  2. لماذا stheril.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. يبدو أن استخدام ProgressRoutine فارغ ليس له أي تأثير على عدم استخدام أي تقدم على الإطلاق.

  5. هل هناك طريقة بديلة وأداء أفضل لنسخ الملفات ولكن أيضًا الحصول على تحديثات التقدم؟

نتائج ملف gib 1 و 10 gib:

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

بيئة الاختبار:

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

ملحوظات:

'robocopy.exe' and 'cmd.exe /c copy' were run using subprocess.call()

win32file.copyfileex A (باستخدام لا تقدم):

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.copyfilex B (باستخدام ProgressRoutine الفارغ):

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
هل كانت مفيدة؟

المحلول

السؤال 3:

أنت تسيء تفسير العلم copy_file_no_buffering في واجهة برمجة تطبيقات microsofts. إنه ليس int 1000 ولكن Hex 1000 (0x1000 => القيمة int: 4096). عندما تقوم بتعيين CopyFlags = 4096 ، سيكون لديك (؟) أسرع نسخ روتين في بيئة Windows. أنا أستخدم نفس الروتين في رمز النسخ الاحتياطي للبيانات الخاص بي والذي يكون سريعًا جدًا ويتحول إلى Terabyte بحجم البيانات يومًا بعد يوم.

السؤال 4:

لا يهم لأنه رد رد. ولكن بشكل عام ، يجب ألا تضع الكثير من التعليمات البرمجية في الداخل والحفاظ عليها نظيفة ورائعة.

السؤال 5:

في تجربتي هو أسرع روتين نسخ ممكن في بيئة Windows القياسية. قد يكون هناك إجراءات نسخ مخصصة أسرع ، ولكن عند استخدام Windows API العادي ، لا يمكن العثور على شيء أفضل.

نصائح أخرى

في جميع الاحتمالات ، لأنك تقيس وقت الانتهاء بشكل مختلف.

أظن أن ملف 1 جيجابايت يناسب ذاكرة الوصول العشوائي بشكل مريح. لذلك ، ربما يكون نظام التشغيل التخزين المؤقت له فقط ويخبر تطبيقك بنسخه عندما لا يزال معظمه (ربما كل شيء) غير متكافئ في المخازن المؤقتة kernel.

ومع ذلك ، فإن ملف 10G لا يتناسب مع ذاكرة الوصول العشوائي ، لذلك يجب أن يكتب (معظمه) قبل أن يقول أنه قد انتهى.

إذا كنت تريد قياسًا ذا معنى ،

أ) قم بمسح ذاكرة التخزين المؤقت لـ FileSystem Buffer قبل كل تشغيل - إذا لم يوفر نظام التشغيل الخاص بك طريقة مريحة للقيام بذلك ، فإن إعادة التشغيل (NB: لا توفر Windows طريقة مريحة ، أعتقد أن هناك أداة داخلية للأنظمة تقوم بذلك) . في حالة نظام ملفات الشبكة ، قم بمسح ذاكرة التخزين المؤقت على الخادم أيضًا.

ب) قم بمزامنة الملف إلى القرص بعد الانتهاء ، قبل قياس وقت الانتهاء

ثم أتوقع أن ترى أوقاتًا أكثر اتساقًا.

للإجابة على سؤالك 2:

Quotil.copyfile () بطيء للغاية ، لأنه افتراضيًا يستخدم مخزنًا لنسخة 16KBYTE. في النهاية ، ينتهي الأمر في att sthil.copyfileobj () ، والذي يبدو هكذا:

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. إذا كنت تريد استخدام CopyFileObj () مباشرة على ملف GB الخاص بك ، ولكن مع مخزن مؤقت يبلغ 128 ميغابايت على سبيل المثال ، سترى أداء محسّن بشكل كبير.

لوكاس ، أجد أن الطريقة التالية تعمل أسرع بنسبة 20 ٪ من win32file.copyfile.

b = bytearray(8 * 1024 * 1024) 
# I find 8-16MB is the best for me, you try to can increase it 
with io.open(f_src, "rb") as in_file:
    with io.open(f_dest, "wb") as out_file:
        while True:
            numread = in_file.readinto(b)
            if not numread:
                break
            out_file.write(b)
            # status bar update here
shutil.copymode(f_src, f_dest)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top