9

मैं विंडोज 8 प्रोजेक्ट के लिए एसिंक सेवा के साथ घूम रहा हूं और इस सेवा के कुछ एसिंक कॉल हैं, जिन्हें केवल एक समय में ही बुलाया जाना चाहिए।क्या एक कार्य में कई प्रतीक्षाकर्ता हैं?

public async Task CallThisOnlyOnce() 
{ 
     PropagateSomeEvents(); 

     await SomeOtherMethod(); 

     PropagateDifferentEvents(); 
} 

जब से तुम एक ताला बयान में एक async कॉल संपुटित नहीं कर सकते, मैं AsyncLock पद्धति का उपयोग कर के बारे में सोचा है, लेकिन से मैंने सोचा मैं के रूप में अच्छी तरह से कुछ इस तरह की कोशिश कर सकते:

private Task _callThisOnlyOnce; 
public Task CallThisOnlyOnce() 
{ 
     if(_callThisOnlyOnce != null && _callThisOnlyOnce.IsCompleted) 
     _callThisOnlyOnce = null; 

     if(_callThisOnlyOnce == null) 
     _callThisOnlyOnce = CallThisOnlyOnceAsync(); 

     return _callThisOnlyOnce; 
} 

private async Task CallThisOnlyOnceAsync() 
{ 
     PropagateSomeEvents(); 

     await SomeOtherMethod(); 

     PropagateDifferentEvents(); 
} 

इसलिए आप चाहते हैं कॉल के साथ समाप्त CallThisOnlyOnceAsync केवल एक बार एक साथ निष्पादित किया गया, और एक ही कार्य पर एकाधिक प्रतीक्षाकर्ता लगाए गए।

क्या यह करने का यह "वैध" तरीका है या इस दृष्टिकोण में कुछ कमीएं हैं?

उत्तर

6

एक कार्य में कई प्रतीक्षाकर्ता हो सकते हैं। हालांकि, जैसा कि डेमियन ने बताया, आपके प्रस्तावित कोड के साथ गंभीर दौड़ की स्थिति है।

यदि आप प्रत्येक बार अपनी विधि (लेकिन एक साथ नहीं) कहा जाता है तो कोड निष्पादित करना चाहते हैं, तो AsyncLock का उपयोग करें। यदि आप कोड को केवल एक बार निष्पादित करना चाहते हैं, तो AsyncLazy का उपयोग करें।

आपका प्रस्तावित समाधान एकाधिक कॉल को गठबंधन करने का प्रयास करता है, अगर कोड पहले से नहीं चल रहा है तो कोड को फिर से निष्पादित करता है। यह अधिक कठिन है, और समाधान आपको आवश्यक सटीक अर्थशास्त्र पर निर्भर करता है। यहाँ एक विकल्प है:

private AsyncLock mutex = new AsyncLock(); 
private Task executing; 

public async Task CallThisOnlyOnceAsync() 
{ 
    Task action = null; 
    using (await mutex.LockAsync()) 
    { 
    if (executing == null) 
     executing = DoCallThisOnlyOnceAsync(); 
    action = executing; 
    } 

    await action; 
} 

private async Task DoCallThisOnlyOnceAsync() 
{ 
    PropagateSomeEvents(); 

    await SomeOtherMethod(); 

    PropagateDifferentEvents(); 

    using (await mutex.LockAsync()) 
    { 
    executing = null; 
    } 
} 

यह भी Interlocked के साथ ऐसा करना संभव है, लेकिन यह है कि कोड बदसूरत हो जाता है।

पीएस मेरे पास AsyncLock, AsyncLazy है, और अन्य async- मेरे AsyncEx library में पहले से ही प्राइमेटिव हैं।

+0

मुझे दोनों उत्तरों पसंद आए, लेकिन चूंकि आपने एक कार्यान्वयन प्रस्ताव जोड़ा, इसलिए मैंने आपका चयन किया। साथ ही, मैंने Nuget का उपयोग करके अपनी लाइब्रेरी को इंस्टॉल करने का प्रयास किया, लेकिन मेरे विंडोज स्टोर प्रोजेक्ट में विफल रहा (माइक्रोसॉफ्ट.बीक्ल.एसिंक को हल करने में असमर्थ) – UrbanEsc

+1

"प्रीरलीज शामिल करें" चेकबॉक्स को चेक करने का प्रयास करें। मेरा पैकेज प्रीरलीज है (लेकिन NuGet सही ढंग से इसका पता नहीं लगाता है), और 'माइक्रोसॉफ्ट.बीक्ल.एसिंक' भी प्रीरलीज है (जो NuGet सही ढंग से पता लगाता है)। –

4

यह कोड बहुत "रेसी" दिखता है यदि एकाधिक धागे शामिल हो सकते हैं।

एक उदाहरण (मुझे यकीन है कि और भी हैं)। मान लें कि _callThisOnlyOnce वर्तमान में null है:

Thread 1               Thread 2 

public Task CallThisOnlyOnce() 
{ 
    if(_callThisOnlyOnce != null && _callThisOnlyOnce.IsCompleted) 
    _callThisOnlyOnce = null; 

    if(_callThisOnlyOnce == null) 
                    public Task CallThisOnlyOnce() 
                    { 
                    if(_callThisOnlyOnce != null && _callThisOnlyOnce.IsCompleted) 
                     _callThisOnlyOnce = null; 

                    if(_callThisOnlyOnce == null) 
                     _callThisOnlyOnce = CallThisOnlyOnceAsync(); 

                    return _callThisOnlyOnce; 
                    } 
    _callThisOnlyOnce = CallThisOnlyOnceAsync(); 

    return _callThisOnlyOnce; 
} 

अब आप 2 कॉल एक साथ चल रहा है।

एकाधिक प्रतीक्षाकर्ताओं के रूप में, हाँ आप यह कर सकते हैं। मुझे यकीन है कि मैंने एमएस से उदाहरण कोड को कहीं भी ऑप्टिमाइज़ेशन दिखाया है, उदाहरण के लिए। Task.FromResult(0) का नतीजा एक स्थिर सदस्य में संग्रहीत किया जाता है और जब भी फ़ंक्शन शून्य वापस करना चाहता है तो वापस लौटाया जाता है।

हालांकि, मैं इस कोड नमूने को ढूंढने में असफल रहा हूं।

संबंधित मुद्दे