سؤال

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

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

بسبب تسرب ذاكرة في البرنامج تعطل SIGSEGV.حل واحد إلى نوع من "إعادة تشغيل" الملف من حيث تحطمت, كان يكتب في آخر معالجة السجل إلى ملف بسيط.

لتحقيق هذا رقم السجل الحالي في تجهيز الحلقة يجب أن تكون مكتوبة إلى ملف.كيف يمكنني التأكد من أن البيانات يتم الكتابة على ملف داخل الحلقة ؟

هل استخدام fseek إلى المركز الأول / الترجيع في حلقة تدهور الأداء ؟

عدد السجلات يمكن أن يكون كثيرا في بعض الأحيان (تصل إلى 500).

شكرا

تحرير:تسرب الذاكرة قد تم بالفعل ثابتة.بداية الشوط الثاني حل واقترح سلامة إضافية قياس والوسائل لتوفير إعادة تشغيل الآلية جنبا إلى جنب مع تخطي n سجلات الحل.آسف على عدم الإشارة إلى ذلك في وقت سابق.

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

المحلول

عندما تواجه هذا النوع من المشاكل, يمكنك أن تعتمد واحدة من طريقتين:

  1. الأسلوب الذي اقترح:لكل سجل تقرأ ، كتابة رقم السجل (أو الموقف من قبل عاد ftell على input file) منفصلة المرجعية الملف.لضمان استئناف بالضبط المكان الذي تركته ، كما أن عدم إدخال سجلات مكررة ، يجب أن fflush بعد كل كتابة (إلى كل من bookmark و إخراج/رفض الملفات.) هذا unbuffered عمليات الكتابة بشكل عام ، إبطاء نموذجية (أي الفشل) السيناريو بشكل ملحوظ.للتأكد من اكتمالها في الله ، لاحظ أن لديك ثلاث طرق الكتابة إلى الإشارة المرجعية الخاصة بك الملف:
    • fopen(..., 'w') / fwrite / fclose - بطيئة للغاية
    • rewind / truncate / fwrite / fflush - هامشيا أسرع
    • rewind / fwrite / fflush - أسرع بعض الشيء;يمكنك تخطي truncate منذ الرقم القياسي (أو ftell موقف) دائما تكون طويلة أو لفترة أطول من الرقم القياسي السابق برقم (أو ftell موقف) ، تماما الكتابة عليه ، شريطة اقتطاع الملف مرة واحدة عند بدء التشغيل (هذا يجيب عن سؤالك الأصلي)
  2. أفترض أن كل شيء سيكون جيدا في معظم الحالات;عند استئناف بعد فشل ببساطة حساب عدد السجلات بالفعل الانتاج (الإخراج الطبيعي بالإضافة إلى ترفض) و تخطي عدد مساو من السجلات من ملف الإدخال.
    • هذا يحافظ على نموذجي (أي الفشل) سيناريوهات سريع جدا دون المساس بشكل كبير الأداء في حالة استئناف بعد فشل السيناريوهات.
    • أنت لا تحتاج إلى fflush الملفات, أو على الأقل ليس في كثير من الأحيان.كنت لا تزال بحاجة إلى fflush الرئيسية الملف الناتج قبل التحول إلى كتابة يرفض الملف ، fflush من يرفض الملف قبل التبديل إلى الكتابة الرئيسية الملف الناتج (ربما بضع مئات أو آلاف المرات عن 500k-إدخال سجل.) ببساطة إزالة آخر غير منهي من خط الانتاج/رفض ملفات كل شيء حتى هذا الخط سوف تكون متسقة.

وإنني أوصي بشدة الأسلوب #2.الكتابة المترتبة على الأسلوب #1 (أيهما من ثلاثة احتمالات) مكلفة للغاية مقارنة مع أي إضافية (مخزنة) يقرأ يقتضيه الأسلوب #2 (fflush يمكن أن يستغرق عدة مللي ثانية ، أن تتضاعف 500k و تحصل على دقائق - حين عد عدد من الخطوط في 500k-ملف سجل يأخذ ثوان معدودات ، ما هو أكثر من ذلك ، ملفات ذاكرة التخزين المؤقت هو العمل مع وليس ضد أنت على ذلك.)


تحرير أردت فقط توضيح الخطوات الدقيقة التي تحتاج إلى تنفيذ الطريقة 2:

  • عند الكتابة إلى الإخراج و ترفض الملفات على التوالي تحتاج فقط إلى الاحمرار عند الانتقال من الكتابة إلى ملف واحد إلى الكتابة إلى آخر.اطلع على السيناريو التالي كما التوضيح من ncessity من فعل هذه الهبات-في-ملف-التبديل:

    • افترض أنك تكتب 1000 السجلات الرئيسية ملف الإخراج ، ثم
    • عليك أن تكتب 1 خط يرفض الملف يدويا دون بيغ الرئيسية إخراج الملف أولا ثم
    • يمكنك كتابة أكثر من 200 خطوط الانتاج الرئيسية الملف دون يدويا التنظيف يرفض الملف أولا ثم
    • وقت التشغيل تلقائيا الإحمرار الناتج الرئيسي الملف لك لأنك تراكمت كمية كبيرة من البيانات في المخازن الرئيسية ملف الإخراج ، أي1200 السجلات
      • ولكن في وقت لم تلقائيا مسح على رفض الملف إلى القرص لك مثل الملف المخزن المؤقت فقط يحتوي على سجل واحد, وهو لا يكفي حجم تدفق تلقائيا
    • البرنامج تعطل في هذه النقطة
    • استئناف والاعتماد 1200 السجلات الرئيسية في ملف الإخراج (وقت التشغيل مسح هذه) ، ولكن 0 (!) السجلات في رفض الملف (لا مسح).
    • استئناف معالجة ملف الإدخال في سجل #1201 ، على افتراض لديك فقط 1200 السجلات بنجاح إلى الناتج الرئيسي ؛ ورفض سجل فقدت 1200 يستحق صالحة سجل سوف تتكرر
    • كنت لا تريد هذا!
  • الآن النظر في التنظيف يدويا بعد التبديل الإخراج/رفض الملفات:
    • افترض أنك تكتب 1000 السجلات الرئيسية ملف الإخراج ، ثم
    • واجهت واحد غير صالح السجل الذي ينتمي إلى ترفض الملف ؛ السجل الأخير كان صالحا ؛ هذا يعني أنك التحول إلى كتابة يرفض الملف:تدفق الانتاج الرئيسية الملف قبل الكتابة إلى ترفض الملف
    • يمكنك الآن كتابة 1 خط يرفض الملف ، ثم
    • كنت تواجه واحدة صالحة السجل الذي ينتمي إلى الناتج الرئيسي ؛ السجل الأخير كان غير صالح ؛ هذا يعني أنك التحول إلى الكتابة الرئيسية الملف الناتج:مسح يرفض الملف قبل كتابة الرئيسي ملف الإخراج
    • يمكنك كتابة أكثر من 200 خطوط الانتاج الرئيسية الملف دون يدويا التنظيف يرفض الملف أولا ثم
    • نفترض أن وقت لم يكن تلقائيا دافق أي شيء بالنسبة لك ، لأن 200 سجلات مخزنة منذ آخر دليل دافق على الانتاج الرئيسية الملف ليست كافية لتحريك التلقائي تدفق
    • البرنامج تعطل في هذه النقطة
    • استئناف والاعتماد 1000 صالحة السجلات الرئيسية في ملف الإخراج (يدويا مسح تلك قبل التحول إلى ترفض الملف) ، 1 سجل في رفض الملف (يمكنك يدويا مسح قبل التبديل الرئيسية ملف الإخراج).
    • هل صحيح السيرة الذاتية معالجة ملف الإدخال في سجل #1001 ، وهو أول صالحة سجل على الفور بعد أن سجل غير صالح.
    • reprocess المقبل 200 سجلات صحيحة لأنها لم تكن مسح, ولكن يمكنك الحصول على أي سجلات مفقودة و لا مكررة إما
  • إذا لم تكن سعيدة مع الفاصل الزمني بين وقت التشغيل التلقائي الإحمرار ، قد أيضا لا دليل تمسح كل 100 أو كل 1000 السجلات.هذا يعتمد على ما إذا كانت المعالجة سجل أكثر تكلفة من التنظيف أو لا (إذا معالجة عملية هي أكثر تكلفة ، دافق في كثير من الأحيان, ربما بعد كل سجل ، وإلا فقط دافق عند التبديل بين إخراج/ترفض.)

  • استئناف من الفشل

    • افتح الملف الناتج و يرفض الملف لكل من القراءة والكتابة, و تبدأ القراءة والعد كل سجل (القول في records_resume_counter) حتى تصل إلى نهاية الملف
    • إلا إذا كنت فلاشينغ بعد كل سجل أنت إخراج, سوف تحتاج أيضا إلى إجراء قليلا من معاملة خاصة الماضية سجل في كل من الناتج وترفض الملف:
      • قبل قراءة سجل من توقف الانتاج/يرفض الملف تذكر موقف كنت في في إخراج/يرفض الملف (استخدام ftell) ، دعنا نسميها last_valid_record_ends_here
      • قراءة المحضر.التحقق من أن سجل ليست جزئية سجل (أيوقت التشغيل قد لا مسح الملف حتى الأوسط من سجل).
      • إذا كان لديك سجل واحد في كل سطر ، هذا هو التحقق بسهولة عن طريق التحقق من أن الحرف الأخير في السجل حرف إرجاع أو تغذية الأسطر (\n أو `r`)
        • إذا كان السجل الكامل ، زيادة السجلات دون المضي قدما في السجل التالي (أو نهاية الملف ، أيهما يأتي أولا.)
        • إذا كان السجل هو جزئي ، fseek العودة إلى last_valid_record_ends_here, و التوقف عن القراءة من هذا الإخراج/رفض الملفات ؛ لا زيادة العداد.والمضي قدما الى المرحلة التالية الإخراج أو يرفض الملف إلا إذا كنت قد ذهبت من خلال كل منهم
    • فتح ملف الإدخال على القراءة و تخطي records_resume_counter السجلات من ذلك
      • مواصلة معالجة و إخراج إخراج/يرفض الملف ؛ هذا سوف تلقائيا إلحاق إخراج/يرفض الملف في المكان الذي تركته القراءة/عد بالفعل معالجة السجلات
      • إذا كان لديك لأداء معالجة خاصة جزئية سجل الإحمرار, السجل التالي إخراج الكتابة الجزئي المعلومات من التشغيل السابقة (في last_valid_record_ends_here) - سيكون لديك أي تكرار أو القمامة أو سجلات مفقودة.

نصائح أخرى

إذا كان يمكنك تغيير التعليمات البرمجية أن يكون ذلك كتابة آخر معالجة السجل إلى ملف ، لماذا لا يمكنك تغييره إلى إصلاح تسرب الذاكرة?

يبدو لي أن أفضل حل أن الإصلاح الجذري للمشكلة بدلا من علاج الأعراض.

fseek() و fwrite() سوف تحط من أداء ولكن ليس بقدر ما فتح/الكتابة/إغلاق نوع العملية.

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

وبدلا من كتابة خارج السجل بأكمله، ربما يكون من الأسهل للاتصال ftell () في بداية كل، والكتابة موقف مؤشر الملف. عندما يكون لديك إلى إعادة تشغيل البرنامج، fseek () إلى موقف مكتوبة الأخير في ملف ومتابعة.

وبطبيعة الحال، وتحديد تسرب الذاكرة سيكون أفضل.)

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

وأود أن وقف حفر حفرة أعمق ومجرد تشغيل البرنامج من خلال Valgrind . القيام بذلك يجب تفادي تسرب، فضلا عن مشاكل أخرى.

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