استراتيجية الوصول إلى الملفات في بيئة متعددة الخيوط (تطبيق الويب)

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

سؤال

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

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

هذا الأمر يحيرني، لأنني أضفت كائنًا لتأمينه، وهو مقفل دائمًا أثناء القراءة/الكتابة.لقد فهمت أنه سيتم مطالبة محاولة الوصول من سلاسل رسائل أخرى بـ "الانتظار" حتى يتم تحرير القفل؟

فقط لإعلامك، أنا جديد حقًا في مجال التطوير متعدد الخيوط، لذلك أنا على استعداد تام لقبول أن هذا خطأ من جهتي :)

  • هل فاتني شيء؟
  • ما هي أفضل استراتيجية للوصول إلى الملفات في بيئة متعددة الخيوط؟

يحرر

آسف - كان يجب أن أقول أن هذا يستخدم أسب.نت 2.0 :)

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

المحلول

هذا هو الرمز الذي أستخدمه للتأكد من عدم قفل الملف بواسطة عملية أخرى.إنها ليست مضمونة بنسبة 100%، ولكنها تنجز المهمة في معظم الأوقات:

    /// <summary>
    /// Blocks until the file is not locked any more.
    /// </summary>
    /// <param name="fullPath"></param>
    bool WaitForFile(string fullPath)
    {
        int numTries = 0;
        while (true)
        {
            ++numTries;
            try
            {
                // Attempt to open the file exclusively.
                using (FileStream fs = new FileStream(fullPath,
                    FileMode.Open, FileAccess.ReadWrite, 
                    FileShare.None, 100))
                {
                    fs.ReadByte();

                    // If we got this far the file is ready
                    break;
                }
            }
            catch (Exception ex)
            {
                Log.LogWarning(
                   "WaitForFile {0} failed to get an exclusive lock: {1}", 
                    fullPath, ex.ToString());

                if (numTries > 10)
                {
                    Log.LogWarning(
                        "WaitForFile {0} giving up after 10 tries", 
                        fullPath);
                    return false;
                }

                // Wait for the lock to be released
                System.Threading.Thread.Sleep(500);
            }
        }

        Log.LogTrace("WaitForFile {0} returning true after {1} tries",
            fullPath, numTries);
        return true;
    }

من الواضح أنه يمكنك تعديل المهلات وإعادة المحاولة لتناسب طلبك.أستخدم هذا لمعالجة ملفات FTP الضخمة التي تستغرق كتابتها بعض الوقت.

نصائح أخرى

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

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

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

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

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

بمجرد أن أخرجت ذلك، أجريت اختبار التحمل الخاص بي مرة أخرى، كل شيء سار على ما يرام!

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

ماذا عن استخدام AutoResetEvent للتواصل بين المواضيع؟لقد قمت بإنشاء تطبيق وحدة تحكم يقوم بإنشاء ملف بحجم 8 جيجابايت تقريبًا createfile الطريقة ثم انسخ هذا الملف فيه main طريقة

 static AutoResetEvent waitHandle = new AutoResetEvent(false);
    static string filePath=@"C:\Temp\test.txt";
    static string fileCopyPath=@"C:\Temp\test-copy.txt";
    static void Main(string[] args)
    {
        Console.WriteLine("in main method");
        Console.WriteLine();
        Thread thread = new Thread(createFile);
        thread.Start();

        Console.WriteLine("waiting for file to be processed ");
        Console.WriteLine();
        waitHandle.WaitOne();
        Console.WriteLine();

        File.Copy(filePath, fileCopyPath);
        Console.WriteLine("file copied ");

    }


    static void createFile()
    {

        FileStream fs= File.Create(filePath);            
        Console.WriteLine("start processing a file "+DateTime.Now);
        Console.WriteLine();
        using (StreamWriter sw = new StreamWriter(fs))
        {
            for (long i = 0; i < 300000000; i++)
            {
                sw.WriteLine("The value of i is " + i);

            }
        }
        Console.WriteLine("file processed " + DateTime.Now);
        Console.WriteLine();

        waitHandle.Set();
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top