2012-10-23 20 views
7

की पसंद मैं जिस तरह से संकलक जब async खोजशब्द का उपयोग कर संकलन TaskScheduler चयन के पीछे तर्क जानना चाहूंगा।async कीवर्ड और TaskScheduler

ऑन-कनेक्टेडएसिंक विधि पर मेरा परीक्षण विधि सिग्नलआर (एएसपी.नेट होस्ट, आईआईएस 8, वेबस्केट ट्रांसपोर्ट) द्वारा बुलाया जाता है।

protected override async Task OnConnectedAsync(IRequest request, string connectionId) 
{ 
    SendUpdates(); 
} 

वर्तमान तुल्यकालन संदर्भ पर एक काम शुरू) System.Web.AspNetSynchronizationContext.OperationStarted में एक InvalidOperationException (

एक अतुल्यकालिक आपरेशन इस समय प्रारंभ नहीं किया जा सकता है के लिए परिणाम देगा। असीमित संचालन केवल एक एसिंक्रोनस हैंडलर या मॉड्यूल के भीतर या पृष्ठ जीवन चक्र में कुछ घटनाओं के दौरान शुरू किया जा सकता है। यदि कोई पृष्ठ निष्पादित करते समय यह अपवाद हुआ, तो सुनिश्चित करें कि पृष्ठ <%@ Page Async="true" %> चिह्नित है।

ठीक। इस SendUpdates परिभाषा के साथ, मुझे उपरोक्त अपवाद मिलता है:

private async void SendUpdates() 
    { 
     Task.Run(async() => 
      { 
       while (true) 
       { 
        await Task.Delay(1000); 
        await Connection.Broadcast("blabla"); 
       } 
      }); 

    } 

लेकिन मुझे और भी दिलचस्प बात यह है कि मुझे अपवाद नहीं मिलता है। निम्नलिखित काम करता है:

private void SendUpdates() 

और निम्न कार्य भी

private async Task SendUpdates() 

यह पिछले एक भी काम करता है, लेकिन यह अनिवार्य रूप से ऊपर के उदाहरण के रूप में ही है।

private Task SendUpdates() 
    { 
     return Task.Run(async() => 
      { 
       while (true) 
       { 
        await Task.Delay(1000); 
        await Connection.Broadcast("blabla"); 
       } 
      }); 

    } 

आप जानते हैं कि कैसे संकलक जो अनुसूचक यहाँ का उपयोग करना चुनते हैं?

उत्तर

10

async कोड लिखने में प्राथमिक दिशा निर्देशों में से एक "async void से बचने" है - जो है, async Task बजाय async void का उपयोग जब तक आप एक async ईवेंट हैंडलर लागू कर रहे हैं।

async void विधियों SynchronizationContext के OperationStarted और OperationCompleted का उपयोग करें; अधिक जानकारी के लिए मेरे एमएसडीएन आलेख It's All about the SynchronizationContext देखें।

एएसपी.नेट OperationStarted पर कॉल का पता लगाता है और (सही ढंग से) इसे अस्वीकार करता है क्योंकि वहां async ईवेंट हैंडलर रखना अवैध है। जब आप async Task का उपयोग करने के लिए कोड को सही करते हैं, तो ASP.NET अब async ईवेंट हैंडलर नहीं देखता है।

आप मेरे intro to async/await post सहायक पा सकते हैं।

+0

यह उत्तर है, धन्यवाद – Xin

3

आप जब फोन:

private async void SendUpdates() 
Task.Run करने के लिए कॉल के साथ

और अनाम प्रतिनिधि पर async keyword का उपयोग कर, आप वास्तव में एक निरंतरता प्रदान नहीं कर रहे हैं; आप Task शुरू करते हैं, और आप Run विधि को निरंतरता दे रहे हैं, जो तब प्रक्रिया करता है। उस निरंतरता को Task.Run नामक कोड के किसी भी अर्थपूर्ण में वापस नहीं भेजा जाता है।

यही कारण है कि आप अपवाद मिलता है, हैंडलरTask कि Task.Run करने के लिए कॉल का उत्पादन पर await पता नहीं करता है।

कहा कि:

private void SendUpdates() 

वर्क्स क्योंकि कार्य बनाए जाने और कोड पर कब्जा नहीं करता है एक SynchronizationContext (विधि पर कोई async कीवर्ड क्योंकि वहाँ, Task उदाहरणों यह डिफ़ॉल्ट रूप से कब्जा नहीं है) । आप काम को फायर कर रहे हैं, लेकिन यह आग और भूल है।

और निम्नलिखित भी काम करता है:

private async Task SendUpdates() 

अर्थात् Task लौटने में, आप एक awaitable कि कॉलबैक साथ काम कर सकते लौटा दिया है क्योंकि।

सीधे अपने प्रश्न का उत्तर देने के लिए, संकलक await पर कॉल करने से पहले SynchronizationContextSynchronizationContext.Current से लौटाएगा सुनिश्चित करेगा; प्रतीक्षा करने योग्य रिटर्न के बाद जो भी निरंतरता कहा जाता है उसे SynchronizationContext का उपयोग करके बुलाया जाएगा।

+0

वास्तव में, मैं कुछ भी इंतजार नहीं करना चाहता। क्या आपका मतलब है कि जब मैं एसिंक टास्क SendUpdates() लिखता हूं, तो मेरा आंतरिक कार्य ASP.NET सिंक्रनाइज़ेशन संदर्भ के साथ संगत कार्य में लपेटा जाता है, लेकिन जब मैं async void SendUpdates() को कॉल करता हूं, तो यह रैपिंग नहीं होता है, जो बताता है समस्या? – Eilistraee

+0

@Eilistraee जब आप 'async कार्य SendUpdates' लिखते हैं, हां,' सिंक्रनाइज़ेशन कॉन्टेक्स्ट 'कैप्चर किया जाता है और' कार्य 'वापस लौटाया जाता है। जब आपके पास 'async void SendUpdates' है, तो आप किसी भी चीज़ पर प्रतीक्षा नहीं कर रहे हैं। यदि कुछ भी हो, तो आपके पास कम से कम एक कंपाइलर चेतावनी होनी चाहिए जो दर्शाती है कि आप 'async' का उपयोग कर रहे हैं, लेकिन इसके पास' प्रतीक्षा 'नहीं है (' प्रतीक्षा 'अज्ञात प्रतिनिधि पर है, विधि के वास्तविक कॉल कोड में नहीं)। – casperOne

+0

लेकिन एसिंक टास्क SendUpdates() मामले में भी, मैं लौटा कार्य का इंतजार नहीं कर रहा हूं। मेरा मतलब है, यह कार्य संदर्भ खो गया है, और OnConnectedAsync कुछ भी इंतजार किए बिना निष्पादन जारी रखता है (और यह एक अच्छी बात है क्योंकि आंतरिक कार्य पूरा नहीं होगा) – Eilistraee