Python x64 بت على Windows X64 نسخ تقييم أداء ملف / مشكلة
-
28-09-2019 - |
سؤال
عند برمجة نوع من تطبيق النسخ الاحتياطي ، قمت بتقييم لأداء نسخ الملفات على Windows.
لدي العديد من الأسئلة وأتساءل عن آرائك.
شكرًا لك!
لوكاس.
أسئلة:
لماذا يكون الأداء أبطأ بكثير عند نسخ ملف GIB 10 مقارنة بملف GIB 1؟
لماذا stheril.copyfile بطيئة جدا؟
لماذا win32file.copyfileex بطيئة جدا؟ هل يمكن أن يكون هذا بسبب العلم win32file.copy_file_restartable؟ ومع ذلك ، فإنه لا يقبل int 1000 كعلم (copy_file_no_buffering) ، والذي يوصى به للملفات الكبيرة:http://msdn.microsoft.com/en-us/library/aa363852٪28vs.85٪29.aspx
يبدو أن استخدام ProgressRoutine فارغ ليس له أي تأثير على عدم استخدام أي تقدم على الإطلاق.
هل هناك طريقة بديلة وأداء أفضل لنسخ الملفات ولكن أيضًا الحصول على تحديثات التقدم؟
نتائج ملف 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)