मैं कुछ नेट के लिए प्रतिक्रियाशील एक्सटेंशन का उपयोग कर कोड को फिर से लिखने की कोशिश कर रहा हूँ, लेकिन मैं अपने लक्ष्य को प्राप्त करने पर कुछ मार्गदर्शन की जरूरत है पर ब्लॉक करने के लिए Rx का उपयोग करना।(और संभवतः समय समाप्त) एक अतुल्यकालिक आपरेशन
मैं एक वर्ग है कि एक निम्न स्तर पुस्तकालय में कुछ अतुल्यकालिक व्यवहार समाहित है। ऐसा कुछ सोचें जो नेटवर्क को पढ़ता या लिखता है। जब कक्षा शुरू होती है तो यह पर्यावरण से जुड़ने की कोशिश करेगी और जब सफल हो तो यह एक कार्यकर्ता थ्रेड से कॉल करके इसे वापस संकेत देगा।
मैं एक तुल्यकालिक कॉल में इस अतुल्यकालिक व्यवहार चालू करना चाहते हैं और मुझे लगता है कि कैसे प्राप्त किया जा सकता पर नीचे एक बहुत सरल उदाहरण बनाया है:
ManualResetEvent readyEvent = new ManualResetEvent(false);
public void Start(TimeSpan timeout) {
// Simulate a background process
ThreadPool.QueueUserWorkItem(_ => AsyncStart(TimeSpan.FromSeconds(1)));
// Wait for startup to complete.
if (!this.readyEvent.WaitOne(timeout))
throw new TimeoutException();
}
void AsyncStart(TimeSpan delay) {
Thread.Sleep(delay); // Simulate startup delay.
this.readyEvent.Set();
}
एक कार्यकर्ता धागे पर AsyncStart
चल रहा है बस एक तरह से अनुकरण करने के लिए है लाइब्रेरी का असीमित व्यवहार और मेरे वास्तविक कोड का हिस्सा नहीं है जहां निम्न स्तर की लाइब्रेरी थ्रेड की आपूर्ति करती है और कॉलबैक पर अपना कोड कॉल करती है।
ध्यान दें कि Start
विधि TimeoutException
फेंक देगी यदि स्टार्ट टाइमआउट अंतराल के भीतर पूरा नहीं हुआ है।
मैं इस कोड को आरएक्स का उपयोग करने के लिए फिर से लिखना चाहता हूं। यहां मेरा पहला प्रयास है:
Subject<Unit> readySubject = new Subject<Unit>();
public void Start(TimeSpan timeout) {
ThreadPool.QueueUserWorkItem(_ => AsyncStart(TimeSpan.FromSeconds(1)));
// Point A - see below
this.readySubject.Timeout(timeout).First();
}
void AsyncStart(TimeSpan delay) {
Thread.Sleep(delay);
this.readySubject.OnNext(new Unit());
}
यह एक सभ्य प्रयास है लेकिन दुर्भाग्य से इसमें दौड़ की स्थिति शामिल है। यदि स्टार्टअप तेज़ पूरा करता है (उदाहरण के लिए यदि delay
0 है) और यदि बिंदु ए पर कोई अतिरिक्त विलंब होता है तो OnNext
readySubject
पर First
से पहले निष्पादित किया जाएगा। सार IObservable
में मैं आवेदन करने कर रहा हूँ Timeout
और First
देखता है कभी नहीं है कि स्टार्टअप पूरा कर लिया है और एक TimeoutException
बजाय फेंक दिया जाएगा।
ऐसा लगता है कि Observable.Defer
इस तरह की समस्याओं को संभालने के लिए बनाया गया है।
Subject<Unit> readySubject = new Subject<Unit>();
void Start(TimeSpan timeout) {
var ready = Observable.Defer(() => {
ThreadPool.QueueUserWorkItem(_ => AsyncStart(TimeSpan.FromSeconds(1)));
// Point B - see below
return this.readySubject.AsObservable();
});
ready.Timeout(timeout).First();
}
void AsyncStart(TimeSpan delay) {
Thread.Sleep(delay);
this.readySubject.OnNext(new Unit());
}
अब अतुल्यकालिक आपरेशन तुरंत लेकिन केवल तभी जब IObservable
किया जा रहा है शुरू नहीं कर रहा है: यहाँ आरएक्स उपयोग करने के लिए थोड़ा और अधिक जटिल प्रयास है। दुर्भाग्य से वहाँ अभी भी एक रेस स्थिति लेकिन बिंदु बी पर इस बार अतुल्यकालिक आपरेशन कॉल OnNext
शुरू कर दिया इससे पहले कि Defer
लैम्ब्डा रिटर्न यह अभी भी खो दिया है और एक TimeoutException
Timeout
द्वारा फेंक दिया जाएगा तो है।
मुझे पता है कि मैं Replay
जैसे ऑपरेटर का उपयोग बफर घटनाओं के लिए कर सकता हूं लेकिन आरएक्स के बिना मेरा प्रारंभिक उदाहरण किसी भी तरह के बफरिंग का उपयोग नहीं करता है। क्या रेस की स्थिति के बिना मेरी समस्या को हल करने के लिए आरएक्स का उपयोग करने का कोई तरीका है? संक्षेप में IObservable
के बाद एसिंक्रोनस ऑपरेशन शुरू करने के बाद इस मामले में Timeout
और First
से कनेक्ट किया गया है?
पॉल बेट्स का जवाब यहाँ के आधार पर समाधान काम कर रहा है:
void Start(TimeSpan timeout) {
var readySubject = new AsyncSubject<Unit>();
ThreadPool.QueueUserWorkItem(_ => AsyncStart(readySubject, TimeSpan.FromSeconds(1)));
// Point C - see below
readySubject.Timeout(timeout).First();
}
void AsyncStart(ISubject<Unit> readySubject, TimeSpan delay) {
Thread.Sleep(delay);
readySubject.OnNext(new Unit());
readySubject.OnCompleted();
}
जब वहाँ बिंदु सेल्सियस पर एक देरी समय AsyncStart
पूरा करने के लिए ले जाता है से अधिक लंबी है कि दिलचस्प हिस्सा है। AsyncSubject
भेजे गए अंतिम अधिसूचना को बरकरार रखता है और Timeout
और First
अभी भी अपेक्षित प्रदर्शन करेगा।
उत्तर देने के लिए धन्यवाद। आरएक्स जारी होने से पहले सवाल पोस्ट किया गया था और तब से एपीआई सतह बहुत बदल गई है।मेरी विशेष समस्या के संबंध में मुझे डर है कि मैं खिड़की से अवरुद्ध नहीं कर सकता। जिस एपीआई का उपयोग कर रहा था, उसे एक बहु स्तरीय प्रारंभिकता की आवश्यकता थी, लेकिन आरएक्स का उपयोग करने से मुझे इनमें से कुछ को समानांतर करने की अनुमति मिली। –
मुझे लगता है कि आरएक्स वास्तव में मल्टी स्टेज प्रारंभ करने के लिए भी उपयोगी है, हालांकि मुझे यह भी लगता है कि मुझे अभी भी ब्लॉक करने की आवश्यकता नहीं है। प्रायः आपके पास एक भी घटना हो सकती है जो उठाया जाता है जब सभी भागों तैयार होते हैं कि सिस्टम तैयार है। इसके बाद आप बुलाए जाने से पहले अन्यथा ब्लॉक करने के लिए उस विकल्प को चुनने के लिए प्रभावी रूप से एक चुनिंदा (कई) कर सकते हैं। –
ओह पीएस, मैंने जो कोड प्रदान किया है वह पिछले 3 वर्षों में आरएक्स एपीआईएस पर काम करेगा (कुछ भिन्नता में)। –