How an Intertangle Forms
दो सबसिस्टम्स स्वतंत्र मॉड्यूल के रूप में अपनी यात्रा शुरू करते हैं। समय के साथ, प्रत्येक एक साझा गॉड-ऑब्जेक्ट पर एक फ़ील्ड जमा करता है: एक ग्लोबल कॉन्फ़िग स्ट्रक्चर, एक सिंगलटन मैनेजर, या एक स्टैटिक क्लास। प्रत्येक जोड़ना: अलग-अलग सही। युग्मन: छोटे स्तर के परीक्षण में अदृश्य।
तीन सबस्ट्रेट्स जहां यह जड़ पकड़ चुका है:
VLC मीडिया प्लेयर। ऑडियो, वीडियो, और प्लेलिस्ट एकल लॉक साझा करते हैं जो ग्लोबल प्लेयर स्टेट की रक्षा करता है। एक टाइमस्टैम्प-पर-स्किप अनुरोध लॉक प्राप्त करता है, प्लेबैक पोज़िशन को संशोधित करता है, और ऑडियो बफर को फ्लश करता है। वीडियो सबसिस्टम, उसी लॉक की प्रतीक्षा करते हुए, रुक जाता है। प्लेलिस्ट सबसिस्टम, जो भी प्रतीक्षा कर रहा है, प्रीफ़ेच नहीं कर सकता। परिणाम: तीन स्वतंत्र सबसिस्टम्स एकल स्टेट ऑब्जेक्ट के माध्यम से सीरियलाइज़ हो जाते हैं। प्रदर्शन लागत: O(N) लॉक विवाद जहां N = सबसिस्टम्स की संख्या, सभी ऑपरेशन लेटेंसी के अनुपात में।
Redis इवेंट लूप. AOF fsync (डिस्क राइट), रेप्लिकेशन (नेटवर्क राइट), और कमांड एक्ज़ीक्यूशन (CPU) एक ही सिंगल-थ्रेडेड इवेंट लूप को शेयर करते हैं। प्रत्येक: अलग-अलग सही है। एक धीमा fsync कमांड एक्ज़ीक्यूशन को रोक देता है। राइट लोड के तहत रेप्लिकेशन लैग बढ़ जाता है। कपलिंग पॉइंट: अलग-अलग लेटेंसी प्रोफाइल वाले ऑपरेशन्स द्वारा शेयर किया गया एकल एक्ज़ीक्यूशन संदर्भ।
LevelDB VersionSet. राइट पाथ (memtable flush) और बैकग्राउंड कंपैक्शन VersionSet लॉक को शेयर करते हैं। एक कंपैक्शन जॉब दसियों मिलीसेकंड तक लॉक होल्ड करता है। राइट पाथ रुक जाता है। दोनों ऑपरेशन्स: आवश्यक। कपलिंग: संरचनात्मक, टाइमिंग नहीं।
महत्वपूर्ण अंतर
एक Intertangle में संरचनात्मक कपलिंग होती है, टाइमिंग समस्या नहीं। रेस कंडीशन: दो थ्रेड्स बिना सिंक्रोनाइज़ेशन के शेयर्ड स्टेट एक्सेस करते हैं। समाधान: एक mutex जोड़ें।
एक Intertangle: दो सबसिस्टम्स डिज़ाइन द्वारा स्टेट शेयर करते हैं। mutex जोड़ने से कपलिंग ठीक नहीं होती; यह एक्सेस को सीरियलाइज़ कर देता है। सबसिस्टम्स अभी भी स्टेट शेयर करते हैं। बॉटलनेक और कड़ा हो जाता है।
VLC Intertangle में mutex जोड़ने से स्थिति और खराब होती है: अब ऑडियो, वीडियो, और प्लेलिस्ट एक ही लॉक का इंतज़ार करते हैं। संरचनात्मक समाधान: प्रत्येक सबसिस्टम को अपना स्टेट दें। फेज स्नैपशॉट: फेज बॉर्डर पर शेयर्ड स्टेट का स्नैपशॉट फ्रीज़ करें, प्रत्येक सबसिस्टम को स्नैपशॉट स्वतंत्र रूप से पढ़ने दें, अंत में राइट्स को मर्ज करें।
संरचनात्मक बनाम टाइमिंग
Intertangle के लिए मुख्य डायग्नोस्टिक प्रश्न: क्या mutex जोड़ने से यह ठीक होगा, या और खराब हो जाएगा?
एक रेस कंडीशन: म्यूटेक्स जोड़ने से यह ठीक हो जाता है। सही एक्सेस ऑर्डरिंग भ्रष्टाचार को समाप्त कर देती है।
एक इंटरटैंगल: म्यूटेक्स जोड़ने से एक्सेस सीरियलाइज़ हो जाता है लेकिन संरचनात्मक युग्मन बना रहता है। सबसिस्टम अभी भी स्टेट शेयर करते हैं। लोड के तहत, वे अभी भी एक-दूसरे को ब्लॉक करते हैं। बाधा और संकरी हो जाती है।
एक इंटरटैंगल कैसे खोजें
तीन डिटेक्शन सिग्नल:
1. सबसिस्टम्स के बीच साझा म्यूटेबल फ़ील्ड्स। एक गॉड-ऑब्जेक्ट जिसमें ऐसे फ़ील्ड्स हैं जिन्हें एक से अधिक सबसिस्टम पढ़ते और लिखते हैं। यदि एक सबसिस्टम की फ़ील्ड एक्सेस हटाने से दूसरा सबसिस्टम टूट जाए, तो वे स्टेट शेयर करते हैं।
2. असंबंधित ऑपरेशन्स को गार्ड करने वाला सिंगल म्यूटेक्स। एक लॉक जो ऑडियो फ़्लश, वीडियो डीकोड और प्लेलिस्ट फ़ेच को गार्ड कर रहा हो: तीन सबसिस्टम्स जिनके अलग-अलग लेटेंसी प्रोफाइल हैं, सभी एक-दूसरे का इंतजार कर रहे हैं। स्मेल: एक ही लॉक नाम के तहत असंबंधित ऑपरेशन्स।
3. लोड बढ़ाने पर परफॉर्मेंस रिग्रेशन। ऑपरेशन A की लेटेंसी तब बढ़ जाती है जब ऑपरेशन B समवर्ती रूप से चल रहा हो, भले ही A और B स्वतंत्र दिखते हों। वे स्वतंत्र नहीं हैं: वे स्टेट शेयर करते हैं।
फेज-स्नैपशॉट फिक्स
फेज स्नैपशॉट पैटर्न:
# पहले: सबसिस्टम्स सीधे शेयर्ड स्टेट को पढ़ते और लिखते थे
class GameWorld:
position = {} # shared mutable
velocity = {} # shared mutable
def physics_tick(world):
for entity in world.entities:
world.position[entity] += world.velocity[entity] # writes shared state mid-loop
# AFTER: चरण से पहले स्नैपशॉट फ्रीज किया गया; लिखने का काम next_state बफर में जाएगा
def physics_tick(world):
snapshot = world.freeze() # अपरिवर्तनीय दृश्य
next_state = {}
for entity in snapshot.entities:
next_state[entity] = snapshot.position[entity] + snapshot.velocity[entity]
world.merge(next_state) # चरण सीमा पर एटॉमिक मर्ज
हर सबसिस्टम स्नैपशॉट पढ़ता है। कोई सबसिस्टम इसमें लिखता नहीं है। लेखन एक बफर में जमा होते हैं और फेज बाउंड्री पर एटॉमिक रूप से मर्ज होते हैं। अब सबसिस्टम स्वतंत्र रूप से निष्पादित होते हैं: कोई लॉक विवाद नहीं, कोई ऑर्डरिंग निर्भरता नहीं, कोई छिपी हुई युग्मन नहीं।
Fix लागू करें
एक टीम ने एक दोष की रिपोर्ट की: उनके गेम इंजन का एनिमेशन सिस्टम और कोलिजन सिस्टम दोनों एक साझा एंटिटी ट्रांसफॉर्म ऑब्जेक्ट में लिखते हैं। जब दोनों एक ही टिक में चलते हैं, तो कोलिजन परिणाम इस बात पर निर्भर करते हैं कि एनिमेशन पहले चला या नहीं। एक म्यूटेक्स जोड़ने से ऑर्डरिंग ठीक हो गई, लेकिन अब जब भी कोलिजन ब्रॉड-फेज स्वीप चलाता है, एनिमेशन रुक जाता है।