كيفية الحصول على أداء جيد للقراءة المتزامنة من القرص

StackOverflow https://stackoverflow.com/questions/9191

  •  08-06-2019
  •  | 
  •  

سؤال

أود أن أطرح سؤالاً ثم أتبعه بإجابتي الخاصة، ولكن أيضًا أريد أن أرى الإجابات التي لدى الآخرين.

لدينا ملفان كبيران نرغب في قراءتهما من موضوعين منفصلين في وقت واحد.سوف يقرأ مؤشر ترابط واحد fileA بالتسلسل بينما سيقرأ مؤشر الترابط الآخر fileB بالتسلسل.لا يوجد قفل أو اتصال بين سلاسل الرسائل، وكلاهما يقرأان بالتسلسل بأسرع ما يمكن، وكلاهما يتجاهل على الفور البيانات التي يقرؤها.

تجربتنا مع هذا الإعداد على Windows سيئة للغاية.الإنتاجية المجمعة للخيطين هي في حدود 2-3 ميجابايت / ثانية.يبدو أن محرك الأقراص يقضي معظم وقته في البحث ذهابًا وإيابًا بين الملفين، ويفترض أنه يقرأ القليل جدًا بعد كل عملية بحث.

إذا قمنا بتعطيل أحد الخيوط ونظرنا مؤقتًا إلى أداء سلسلة واحدة، فسنحصل على نطاق ترددي أفضل بكثير (حوالي 45 ميجابايت/ثانية لهذا الجهاز).من الواضح أن الأداء السيئ للخيطين هو نتيجة مصطنعة لبرنامج جدولة قرص نظام التشغيل.

هل هناك أي شيء يمكننا القيام به لتحسين أداء قراءة الخيط المتزامن؟ ربما باستخدام واجهات برمجة تطبيقات مختلفة أو عن طريق تعديل معلمات جدولة قرص نظام التشغيل بطريقة ما.

بعض التفاصيل:

الملفات بترتيب 2 جيجا بايت لكل منها على جهاز به 2 جيجا بايت من ذاكرة الوصول العشوائي.ولأغراض هذا السؤال، فإننا نعتبرها غير مخزنة مؤقتًا ولا يتم إلغاء تجزئتها بشكل كامل.لقد استخدمنا أدوات إلغاء التجزئة وأعدنا التشغيل للتأكد من أن هذا هو الحال.

نحن لا نستخدم واجهات برمجة تطبيقات خاصة لقراءة هذه الملفات.يكون السلوك قابلاً للتكرار عبر العديد من واجهات برمجة التطبيقات القياسية مثل Win32's CreateFile وC's fopen وC++'s std::ifstream وJava's FileInputStream وما إلى ذلك.

يدور كل خيط في حلقة لإجراء استدعاءات لوظيفة القراءة.لقد قمنا بتغيير عدد البايتات المطلوبة من واجهة برمجة التطبيقات (API) في كل تكرار من قيم تتراوح بين 1 كيلو بايت إلى 128 ميجا بايت.لم يكن لتغيير هذا أي تأثير، لذلك من الواضح أن المقدار الذي يقرأه نظام التشغيل فعليًا بعد كل عملية بحث عن القرص لا يحدده هذا الرقم.وهذا هو بالضبط ما ينبغي توقعه.

الفرق الكبير بين أداء الخيط الواحد والخيطين قابل للتكرار عبر أنظمة التشغيل Windows 2000، وWindows XP (32 بت و64 بت)، وWindows Server 2003، وأيضًا مع أجهزة RAID5 وبدونها.

هل كانت مفيدة؟

المحلول

يبدو أن المشكلة تكمن في سياسة جدولة الإدخال/الإخراج في Windows.حسب ما وجدته هنا هناك طرق عديدة لنظام التشغيل.لجدولة طلبات القرص.بينما يمكن لنظام التشغيل Linux وغيره الاختيار بين سياسات مختلفة، قبل نظام التشغيل Vista، كان نظام التشغيل Windows مغلقًا في سياسة واحدة:قائمة انتظار FIFO، حيث يتم تقسيم جميع الطلبات إلى كتل بحجم 64 كيلو بايت.أعتقد أن هذه السياسة هي سبب المشكلة التي تواجهها:سيقوم المجدول بخلط الطلبات من الخيطين، مما يؤدي إلى البحث المستمر بين مناطق مختلفة من القرص.
الآن، الخبر السار هو أنه وفقا ل هنا و هنا, ، قدم نظام Vista جدولة قرص أكثر ذكاءً، حيث يمكنك تعيين أولوية طلباتك وكذلك تخصيص الحد الأدنى من عرض النطاق الترددي للعملية الخاصة بك.
الخبر السيئ هو أنني لم أجد طريقة لتغيير سياسة القرص أو حجم المخازن المؤقتة في الإصدارات السابقة من Windows.وأيضًا، حتى إذا كان رفع أولوية الإدخال/الإخراج على القرص في عمليتك سيعزز الأداء مقارنة بالعمليات الأخرى، فلا يزال لديك مشاكل في تنافس مؤشرات الترابط الخاصة بك مع بعضها البعض.
ما يمكنني اقتراحه هو تعديل برنامجك عن طريق تقديم سياسة الوصول إلى القرص ذاتية الصنع.
على سبيل المثال، يمكنك استخدام سياسة مثل هذه في موضوعك B (مماثلة للموضوع A):

if THREAD A is reading from disk then wait for THREAD A to stop reading or wait for X ms
Read for X ms (or Y MB)
Stop reading and check status of thread A again  

يمكنك استخدام الإشارات للتحقق من الحالة أو يمكنك استخدام عدادات الأداء للحصول على حالة قائمة انتظار القرص الفعلية.يمكن أيضًا ضبط قيم X و/أو Y تلقائيًا عن طريق التحقق من معدلات النقل الفعلية وتعديلها ببطء، وبالتالي زيادة الإنتاجية إلى أقصى حد عند تشغيل التطبيق على أجهزة و/أو أنظمة تشغيل مختلفة.قد تجد أن مستويات ذاكرة التخزين المؤقت أو الذاكرة أو RAID تؤثر عليها بطريقة أو بأخرى، ولكن مع الضبط التلقائي ستحصل دائمًا على أفضل أداء في كل سيناريو.

نصائح أخرى

وأود أن أضيف بعض الملاحظات الأخرى في ردي.جميع أنظمة التشغيل الأخرى غير التابعة لشركة Microsoft التي اختبرناها لا تعاني من هذه المشكلة.Linux وFreeBSD وMac OS X (هذا الأخير على أجهزة مختلفة) جميعها تتدهور بشكل أكثر رشاقة من حيث إجمالي عرض النطاق الترددي عند الانتقال من خيط واحد إلى خيطين.Linux على سبيل المثال انخفض من ~45 ميجا بايت/ثانية إلى ~42 ميجا بايت/ثانية.يجب أن تقرأ أنظمة التشغيل الأخرى أجزاء أكبر من الملف بين كل عملية بحث، وبالتالي لا تقضي كل وقتها تقريبًا في انتظار القرص للبحث.

الحل الذي نقدمه لنظام التشغيل Windows هو تمرير ملف FILE_FLAG_NO_BUFFERING العلم ل CreateFile واستخدم قراءات كبيرة (~ 16 ميجابايت) في كل مكالمة لـ ReadFile.وهذا أمر دون المستوى الأمثل لعدة أسباب:

  • لا يتم تخزين الملفات مؤقتًا عند قراءتها بهذه الطريقة، لذلك لا توجد أي من المزايا التي يوفرها التخزين المؤقت عادةً.
  • تعد القيود عند العمل باستخدام هذه العلامة أكثر تعقيدًا بكثير من القراءة العادية (محاذاة مخازن القراءة المؤقتة لحدود الصفحة، وما إلى ذلك).

(كملاحظة أخيرة.هل هذا يفسر لماذا يعد التبديل ضمن Windows أمرًا جهنميًا؟أي أن Windows غير قادر على إجراء عمليات الإدخال/الإخراج لملفات متعددة في وقت واحد وبأي كفاءة، لذلك أثناء تبديل جميع عمليات الإدخال/الإخراج الأخرى تضطر إلى أن تكون بطيئة بشكل غير متناسب.)


قم بالتحرير لإضافة بعض التفاصيل الإضافية لـ Will Dean:

بالطبع عبر تكوينات الأجهزة المختلفة هذه، تغيرت الأرقام الأولية (بشكل كبير في بعض الأحيان).ومع ذلك، تكمن المشكلة في التدهور المستمر في الأداء الذي يعاني منه Windows فقط عند الانتقال من مؤشر ترابط واحد إلى خيطين.فيما يلي ملخص للآلات التي تم اختبارها:

  • العديد من محطات عمل Dell (Intel Xeon) من مختلف الأعمار تعمل بنظام التشغيل Windows 2000 وWindows XP (32 بت) وWindows XP (64 بت) بمحرك أقراص واحد.
  • خادم Dell 1U (Intel Xeon) يعمل بنظام التشغيل Windows Server 2003 (64 بت) مع RAID 1+0.
  • محطة عمل HP (AMD Opteron) تعمل بنظام التشغيل Windows XP (64 بت) وWindows Server 2003 والأجهزة RAID 5.
  • جهاز الكمبيوتر الشخصي المنزلي بدون علامة تجارية (AMD Athlon64) الذي يعمل بنظام التشغيل Windows XP (32 بت)، وFreeBSD (64 بت)، وLinux (64 بت) بمحرك أقراص واحد.
  • جهاز MacBook المنزلي الخاص بي (Intel Core1) الذي يعمل بنظام التشغيل Mac OS X، ومحرك أقراص SATA واحد.
  • منزلي كولو جهاز كمبيوتر يعمل بنظام Linux.ضعيف إلى حد كبير مقارنة بالأنظمة الأخرى ولكنني أوضحت أنه حتى هذا الجهاز يمكنه أن يتفوق في الأداء على خادم Windows مع RAID5 عند القيام بقراءات القرص متعدد الخيوط.

كان استخدام وحدة المعالجة المركزية على كافة هذه الأنظمة منخفضًا جدًا أثناء الاختبارات وتم تعطيل برنامج مكافحة الفيروسات.

لقد نسيت أن أذكر ذلك من قبل ولكننا جربنا أيضًا Win32 العادي CreateFile واجهة برمجة التطبيقات مع FILE_FLAG_SEQUENTIAL_SCAN مجموعة العلم.هذه العلامة لم تحل المشكلة.

يبدو من الغريب بعض الشيء أنك لا ترى أي اختلاف عبر مجموعة واسعة من إصدارات Windows ولا يوجد شيء بين محرك أقراص واحد وأجهزة RAID-5.

إنه مجرد "شعور داخلي"، ولكن هذا يجعلني أشك في أن هذه مشكلة بحث بسيطة حقًا.بخلاف OS X وRaid5، هل تمت تجربة كل هذا على نفس الجهاز - هل جربت جهازًا آخر؟هل استخدام وحدة المعالجة المركزية لديك صفر بشكل أساسي أثناء هذا الاختبار؟

ما هو أقصر تطبيق يمكنك كتابته والذي يوضح هذه المشكلة؟- سأكون مهتمًا بتجربته هنا.

سأقوم بإنشاء نوع من القفل الآمن لخيط الذاكرة.يمكن لكل خيط الانتظار على القفل حتى يصبح حرًا.عندما يصبح القفل مجانيًا، خذ القفل واقرأ الملف لفترة زمنية محددة أو كمية محددة من البيانات، ثم حرر القفل لأي سلاسل رسائل أخرى تنتظر.

هل تستعمل IOCompletionPorts تحت ويندوز؟يحتوي Windows عبر C++ على فصل متعمق حول هذا الموضوع ولحسن الحظ، وهو متوفر أيضًا على MSDN.

بول - رأى التحديث.مثير جدا.

سيكون من المثير للاهتمام تجربتها على نظامي التشغيل Vista أو Win2008، حيث يبدو أن الأشخاص يبلغون عن بعض التحسينات الكبيرة في الإدخال/الإخراج في بعض الظروف.

اقتراحي الوحيد حول واجهة برمجة تطبيقات مختلفة هو تجربة تعيين الذاكرة للملفات - هل جربت ذلك؟لسوء الحظ، عند استخدام 2 غيغابايت لكل ملف، لن تتمكن من تعيين ملفات كاملة متعددة على جهاز 32 بت، مما يعني أن هذا ليس بالأمر التافه تمامًا كما قد يكون.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top