2015-12-08 12 views
5

का उपयोग कर this link के अनुसार:async/इंतजार deadlocking जब एक SynchronizationContext

आप का इंतजार कीवर्ड के साथ एक विधि पर इंतजार कर रहे हैं जब, संकलक आप की ओर से में कोड का गुच्छा उत्पन्न करता है। इस कार्रवाई के प्रयोजनों में से एक यूआई थ्रेड के साथ सिंक्रनाइज़ेशन को संभालने के लिए है। इस विशेषता का प्रमुख
घटक SynchronizationContext.Current जो वर्तमान थ्रेड के लिए तुल्यकालन संदर्भ हो जाता है।
SynchronizationContext.Current
वातावरण में हो पर निर्भर करता है आबादी है। टास्क के GetAwaiter विधि के लिए
SynchronizationContext.Current ऊपर लग रहा है। यदि वर्तमान समन्वयन संदर्भ अशक्त नहीं है, निरंतरता कि awaiter के लिए पारित हो जाता है कि कि तुल्यकालन संदर्भ के लिए वापस पोस्ट कर दिया जाएगा।

जब एक विधि है, जो नए अतुल्यकालिक भाषा सुविधाओं का उपयोग करता, एक अवरुद्ध फैशन में लेने वाली है, तो आप अगर
आप एक उपलब्ध SynchronizationContext एक गतिरोध के साथ खत्म हो जाएगा।
जब आप एक अवरुद्ध फैशन (प्रतीक्षा विधि के साथ कार्य पर इंतजार कर या कार्य के परिणाम संपत्ति से सीधे परिणाम लेने) में लेने वाली ऐसी तरीके हैं, आप एक ही समय में मुख्य थ्रेड रोकेंगे। अंत में टास्क ThreadPool में है कि विधि के अंदर पूरा करता है, यह क्योंकि SynchronizationContext.Current उपलब्ध है और कब्जा कर लिया है मुख्य थ्रेड वापस करने के लिए पोस्ट करने के लिए जारी रखने के आह्वान करने के लिए जा रहा है। लेकिन यहां एक समस्या है: यूआई थ्रेड अवरुद्ध है और आपके पास डेडलॉक है!

public class HomeController : Controller 
    {  
     public ViewResult CarsSync() 
     { 
      SampleAPIClient client = new SampleAPIClient(); 
      var cars = client.GetCarsInAWrongWayAsync().Result; 
      return View("Index", model: cars); 
     } 
    } 

    public class SampleAPIClient 
    { 
     private const string ApiUri = "http://localhost:17257/api/cars"; 
     public async Task<IEnumerable<Car>> GetCarsInAWrongWayAsync() 
     { 
      using (var client = new HttpClient()) 
      { 
       var response = await client.GetAsync(ApiUri); 

       // Not the best way to handle it but will do the work for demo purposes 
       response.EnsureSuccessStatusCode(); 
       return await response.Content.ReadAsAsync<IEnumerable<Car>>(); 
      } 
     } 
    } 

मैं मुसीबत ऊपर बयान की बोल्ड हिस्सा समझ है, लेकिन जब मैं कोड ऊपर का परीक्षण, यह उम्मीद के रूप में गतिरोध। लेकिन मुझे अभी भी समझ में नहीं आ रहा है कि यूआई थ्रेड क्यों अवरुद्ध है?

इस मामले में, उपलब्ध SynchronizationContext क्या है? क्या यह यूआई थ्रेड है?

+5

[यहां] से है (http://www.tugberkugurlu.com/archive/asynchronousnet-client-libraries-for-your-http-api-and-awareness: उचित ठीक बदलने के लिए CarsSync है के- async-का इंतजार-स-बुरा प्रभाव)? यदि ऐसा है, तो आपके प्रश्न में एक लिंक शामिल करना और यह इंगित करना अच्छा होगा कि इसमें से अधिकांश एक उद्धरण है। –

+1

यह आपके सवाल का सीधा जवाब नहीं है, लेकिन अगर आप अपने नियंत्रक कार्रवाई परिणाम 'टास्क बनाने' इसे नीचे सभी तरह async हो सकता है (जो ASP.NET धागा उपयोग के संबंध में बेहतर मापता है) –

+0

@Damien_The_Unbeliever हाँ, मैं लिंक धन्यवाद – nainaigu

उत्तर

8

मैं पूरी in my own blog post में यह समझाने, लेकिन यहाँ दोहराते हैं ...

await डिफ़ॉल्ट रूप से एक वर्तमान "संदर्भ" पर कब्जा और इस संदर्भ पर अपनी async विधि फिर से शुरू होगा। यह संदर्भ SynchronizationContext.Current है जब तक यह null नहीं है, इस स्थिति में यह TaskScheduler.Current है। जब आप एक एक धागा पर एक समय SynchronizationContext है और आप एक काम एसिंक्रोनस कोड का प्रतिनिधित्व करने पर ब्लॉक (जैसे, Task.Wait या Task<T>.Result का प्रयोग करके)

गतिरोध हो सकता है।ध्यान दें कि यह अवरोध है जो डेडलॉक का कारण बनता है, न केवल SynchronizationContext; उपयुक्त रिज़ॉल्यूशन (लगभग हमेशा) कॉलिंग कोड एसिंक्रोनस (उदाहरण के लिए, Task.Wait/Task<T>.Resultawait के साथ) को प्रतिस्थापित करना है। यह विशेष रूप से एएसपी.नेट पर सच है।

लेकिन मुझे अभी भी समझ में नहीं आ रहा है कि UI थ्रेड अवरुद्ध क्यों है?

आपका उदाहरण एएसपी.नेट पर चल रहा है; कोई यूआई धागा नहीं है।

उपलब्ध सिंक्रनाइज़ेशन कॉन्टेक्स्ट क्या उपलब्ध है?

वर्तमान SynchronizationContextAspNetSynchronizationContext का एक उदाहरण है, एक संदर्भ है कि एक ASP.NET अनुरोध का प्रतिनिधित्व करता है होना चाहिए। यह संदर्भ केवल एक थ्रेड को एक समय में अनुमति देता है।


तो, अपने उदाहरण के माध्यम से चलने के लिए:

जब एक अनुरोध इस कार्रवाई के लिए में आता है, CarsSync उस अनुरोध संदर्भ में क्रियान्वित करने शुरू कर देंगे।

var cars = client.GetCarsInAWrongWayAsync().Result; 

जो इस रूप में अनिवार्य रूप से एक ही है:: यह इस लाइन के लिए आगे बढ़ता

Task<IEnumerable<Car>> carsTask = client.GetCarsInAWrongWayAsync(); 
var cars = carsTask.Result; 

इसलिए, यह GetCarsInAWrongWayAsync में कॉल करने के लिए है, जो चलाता है जब तक यह अपनी पहली await (GetAsync कॉल) को छूता आगे बढ़ता है । इस बिंदु पर, GetCarsInAWrongWayAsync अपने वर्तमान संदर्भ (एएसपी.नेट अनुरोध संदर्भ) को कैप्चर करता है और एक अपूर्ण Task<IEnumerable<Car>> देता है। जब GetAsync डाउनलोड पूर्ण होने पर, GetCarsInAWrongWayAsync कि ASP.NET अनुरोध संदर्भ और पर क्रियान्वित फिर से शुरू होगा (अंततः) कार्य यह पहले से ही लौट आए पूरा करें।

हालांकि, जैसे ही GetCarsInAWrongWayAsync अधूरा कार्य, CarsSync ब्लॉक वर्तमान धागा देता है, उस कार्य को पूरा करने के लिए के लिए इंतज़ार कर के रूप में। ध्यान दें कि वर्तमान थ्रेड उस एएसपी.NET अनुरोध संदर्भ में है, इसलिए CarsSyncGetCarsInAWrongWayAsync को फिर से शुरू करने से रोक देगा, जिससे डेडलॉक हो जाएगा।

अंतिम नोट के रूप में, GetCarsInAWrongWayAsync एक ठीक तरीका है। यह बेहतर है अगर यह ConfigureAwait(false) इस्तेमाल किया हो सकता है, लेकिन यह वास्तव में गलत नहीं है। CarsSync डेडलॉक के कारण विधि है; यह Task<T>.Resultपर कॉल है गलत है।

public class HomeController : Controller 
{  
    public async Task<ViewResult> CarsSync() 
    { 
    SampleAPIClient client = new SampleAPIClient(); 
    var cars = await client.GetCarsInAWrongWayAsync(); 
    return View("Index", model: cars); 
    } 
} 
+0

मैंने एक और स्टीफन [लेख] (https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and- पढ़ा था) के बाद, मैं async द्वारा deadlocks का कारण समझ गया/अधिक स्पष्ट रूप से प्रतीक्षा कर रहा हूं। कंसोल-क्षुधा /)। –

0

प्रमुख मुद्दा है कि कुछ SynchronizationContext रों केवल एक ही धागा एक ही समय में कोड चलाने की अनुमति दे सकता है। एक थ्रेड Result या Wait बुला रहा है। जब async विधियां प्रवेश करना चाहती हैं तो यह नहीं कर सकती है।

कुछ SynchronizationContext एस mutli- threaded हैं और समस्या नहीं होती है।

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