كيف يتشكل تبديل
تبدأ الوحدات الفرعية حياتها كوحدات مستقلة. مع الوقت، تجمع كل منها حقلًا على كائن مشترك: بنية بيانات عامة، كائن مدير واحد، صفحة إحصائية. كل إضافة: صحيحة في العزل. العلاقة: غير مرئية في الفحوصات على نطاق صغير.
ثلاثة مدخلات حيث تصل هذه إلى حالة متصلة:
مستقبل الفيديو VLC. الصوت، والفيديو، وقائمة التشغيل يشاركون في قفل واحد يحمي حالة اللاعب العالمية. طلب إقصاء إلى توقيت يلقي القفل، ويعدّل في موضع التشغيل، وينزع الفيبريشن الصوتي. النظام الفيديو، ينتظر نفس القفل، يتوقف. النظام القائمة، ينتظر أيضًا، لا يمكنه الاستعداد المسبق. النتيجة: ثلاثة وحدات فرعية مستقلة يتم تعطيلها من خلال كائن حالة واحد. تكلفة الأداء: O(N) من التنافس على القفل حيث N = عدد الوحدات الفرعية، كلها متناسبة مع تأخير العملية.
خادم Redis حلقة الحدث. (تنسيق القراءة المباشر) (كتابة القرص)، (نسخ الرد) (كتابة الشبكة)، (تنفيذ الأمر) (المعالجة) يشاركون في حلقة الحدث المفردة. كلها: صحيحة في العزل. إيقاف كتابة القرص يبطئ تنفيذ الأمر. تأخير النسخ يزداد تحت شح تحميل الكتابة. نقطة الربط: سياق تنفيذ مشترك يشاركه عمليات ذات محتوى تأخير مختلف.
LevelDB VersionSet. مسار الكتابة (إخراج الميمتابل) & التجميع الخلفي يشاركان في قفل VersionSet. وظيفة التجميع تحمل القفل لعدة مئات من المليثانث. مسار الكتابة يتوقف. كلا العمليات: ضرورية. العلاقة: هيكلية وليس مشكلة وقت.
الفارق الحرجة
تبديل لديه علاقة هيكلية وليس مشكلة وقت. مشكلة السرعة: رأس سرعة بدون تزامن. حل: إضافة قفل.
تبديل: نظامين يشاركان في حالة بتخطي التصميم. إضافة قفل لا يصلح العلاقة؛ يserializes الوصول. النظامين يظلان يشاركان في حالة. الحاجز يضيق.
إضافة قفل لتبديل VLC يجعله أسوأ: الآن الصوت، والفيديو، وقائمة التشغيل كلها ينتظرون قفلًا واحدًا. الحل الهيكلي: إعطاء كل وحدة فرعية حالة خاصة. نظام التقديم الفيزيائي: إغلاق نسخة من الحالة المشتركة عند الحدود الفيزيائية، يسمح لكل وحدة فرعية قراءة النسخة بشكل مستقل، دمج الكتابة مرة أخرى في نهاية المطاف.
الهيكلي مقابل وقت
السؤال التشخيصي الرئيسي لمنظومة التكتل: هل ستجعل إضافة قفل (mutex) الأفضل، أو ستجعل المشكلة أسوأ؟
حالة التنافس في الأداء: إضافة قفل تصلح المشكلة. ترتيب الوصول الصحيح يزيل التلف.
تكتل: إضافة القفل يserializes الوصول ولكن يحتفظ بالتوافق الهيكلي. الفصائل لا تزال تشارك في حالة مشتركة. تحت الحمل، لا تزال تمنع بعضها البعض. تضييق الحاجز.
كيفية إيجاد تكتل
ثلاثة إشارات كشف:
1. حقول قابلة للتعديل مشتركة بين الفصائل. كائن إلهي مع حقول يتم قراءتها وكتابةها بواسطة أكثر من نظام فرعي. إذا تم إلغاء الوصول إلى حقول نظام فرعي واحد، فسيشكل ذلك مشكلة أخرى، مما يدل على أنهم يشاركون حالة.
2. قفل واحد يحمي العمليات غير المتعلقة. قفل واحد يحمي إزالة الصوت والتعدين الفيديو والاسترداد القائمة: ثلاثة أنظمة مع أرقام تأخير مختلفة، كلها تنتظر بعضها البعض. الرائحة: العمليات غير المتعلقة تحت اسم قفل.
3. تراجع الأداء عند إضافة الحمل. تأخير عملية A تزداد عندما تشغل عملية B بشكل مستقل، حتى إذا كان A & B يبدوان مستقلين. هم ليسوا مستقلين: هم يشاركون حالة.
التصحيح باستخدام لقطة مراحل
نمط لقطة مراحل:
# قبل ذلك: تم قراءة وكتابة حالة مشتركة مباشرة بواسطة الفصائل
class GameWorld:
position = {} # قابل للتعديل مشترك
velocity = {} # قابل للتعديل مشترك
def physics_tick(world):
for entity in world.entities:
world.position[entity] += world.velocity[entity] # writes shared state mid-loop
# AFTER: snapshot frozen before phase; writes go to next_state buffer
def physics_tick(world):
snapshot = world.freeze() # immutable view
next_state = {}
for entity in snapshot.entities:
next_state[entity] = snapshot.position[entity] + snapshot.velocity[entity]
world.merge(next_state) # atomic merge at phase boundary
Every subsystem reads the snapshot. No subsystem writes to it. Writes accumulate in a buffer & merge atomically at the phase boundary. Subsystems now execute independently: no lock contention, no ordering dependency, no hidden coupling.
تطبيق الصيغة
تقرير فريق العيوب: أنظمة تحريك اللعبة ومتصفح الاصطدامات كلاهما يكتبان على كائن تحويل الكائن المشترك. عندما يتشغلان في نفس التيك، نتيجة الاصطدام تعتمد على ما إذا كان تحريك اللعبة قد تشغل أولاً. إضافة قفل المتاجرة سلكت المشكلة التسلسل، لكن الآن تحريك اللعبة يتوقف عند تشغيل متصفح الاصطدامات.