2013-04-09 24 views
15

में अपवादों को डिबग करना मैं अपने यूआई-थ्रेड को मुक्त करने और मल्टीथ्रेडिंग को पूरा करने के लिए Async/Await का उपयोग करता हूं। अब जब मुझे अपवाद मारा गया तो मुझे एक समस्या है। मेरे Async भागों के Call Stack सभी ThreadPoolWorkQue.Dipatch() से शुरू होते हैं, जो मेरी बहुत मदद नहीं करता है।एसिंक/Await (कॉल स्टैक)

मुझे इसके बारे में एक एमएसडीएन-आलेख Andrew Stasyuk. Async Causality Chain Tracking मिला लेकिन जैसा कि मैं इसे समझता हूं, यह समाधान का उपयोग करने के लिए तैयार नहीं है।

यदि आप Async/Await के साथ मल्टीथ्रेडिंग का उपयोग करते हैं तो डीबग करने का सबसे अच्छा/आसान तरीका क्या है?

उत्तर

18

जो लेख आपको मिला वह यह बताने का एक अच्छा काम करता है कि क्यों कॉल स्टैक काम नहीं करते हैं, हम में से अधिकांश सोचते हैं कि वे क्या करते हैं। तकनीकी रूप से, कॉल स्टैक केवल हमें बताता है कि वर्तमान विधि के बाद कोड कहां लौट रहा है। दूसरे शब्दों में, कॉल स्टैक "जहां कोड जा रहा है" है, न कि "जहां से कोड आया था"।

दिलचस्प बात यह है कि लेख पास करने में एक समाधान का उल्लेख करता है, लेकिन इस पर विस्तार नहीं करता है। मेरे पास a blog post that goes explains the CallContext solution in detail है। अनिवार्य रूप से, आप अपना खुद का "नैदानिक ​​संदर्भ" बनाने के लिए तार्किक कॉल संदर्भ का उपयोग करते हैं।

मुझे लेख में प्रस्तुत समाधान से बेहतर CallContext समाधान पसंद है क्योंकि यह काम async कोड (फोर्क/शामिल कोड जैसे Task.WhenAll) के सभी रूपों में होगा।

यह सबसे अच्छा समाधान है जो मुझे पता है (कुछ वास्तव में प्रोफाइलिंग एपीआई में हुकिंग जैसे जटिल करने के अलावा)। CallContext की चेतावनी:

  • यह केवल .NET 4.5 पूर्ण पर काम करता है। विंडोज स्टोर ऐप्स, .NET 4.0, आदि के लिए कोई समर्थन नहीं
  • आपको अपने कोड को मैन्युअल रूप से "उपकरण" करना होगा। AFAIK इसे स्वचालित रूप से इंजेक्ट करने का कोई तरीका नहीं है।
  • अपवाद स्वचालित रूप से तार्किक कॉल संदर्भ को कैप्चर नहीं करते हैं। तो यह समाधान ठीक काम करता है यदि आप अपवादों को फेंकते समय डीबगर में तोड़ रहे हैं, लेकिन यह उपयोगी नहीं है अगर आप किसी अन्य स्थान पर अपवादों को पकड़ रहे हैं और उन्हें लॉग इन कर रहे हैं।

कोड (immutable collections NuGet library पर निर्भर करता है):

public static class MyStack 
{ 
    private static readonly string name = Guid.NewGuid().ToString("N"); 

    private static ImmutableStack<string> CurrentContext 
    { 
     get 
     { 
      var ret = CallContext.LogicalGetData(name) as ImmutableStack<string>; 
      return ret ?? ImmutableStack.Create<string>(); 
     } 

     set 
     { 
      CallContext.LogicalSetData(name, value); 
     } 
    } 

    public static IDisposable Push([CallerMemberName] string context = "") 
    { 
     CurrentContext = CurrentContext.Push(context); 
     return new PopWhenDisposed(); 
    } 

    private static void Pop() 
    { 
     CurrentContext = CurrentContext.Pop(); 
    } 

    private sealed class PopWhenDisposed : IDisposable 
    { 
     private bool disposed; 

     public void Dispose() 
     { 
      if (disposed) 
       return; 
      Pop(); 
      disposed = true; 
     } 
    } 

    // Keep this in your watch window. 
    public static string CurrentStack 
    { 
     get 
     { 
      return string.Join(" ", CurrentContext.Reverse()); 
     } 
    } 
} 

उपयोग:

static async Task SomeWorkAsync() 
{ 
    using (MyStack.Push()) // Pushes "SomeWorkAsync" 
    { 
     ... 
    } 
} 

अद्यतन: मैं एक NuGet package (described on my blog) धक्का सुई PostSharp का उपयोग करता है और स्वचालित रूप से पॉप कि जारी किया। तो एक अच्छा निशान प्राप्त करना अब बहुत आसान होना चाहिए।

+0

आपके तेज़ उत्तर के लिए धन्यवाद। मैं कोशिश करता हूं और देखता हूं कि यह कैसे काम करता है :-)। मैं किसी भी तरह से आशा करता था कि अधिक जानकारी के साथ 'पैरालेल स्टैक' जैसे समाधान होंगे। लेकिन आप सब कुछ नहीं हो सकता ;-)। क्या मैं सही हूं कि केवल 'MyStack.Push()' लॉग्स और मुझे हर जगह इसकी आवश्यकता है यदि मैं जानना चाहता हूं कि मैं कहां गया हूं? – Patrick

+0

'MyStack.Push' और' MyStack.Pop' (निपटान) ढेर को संशोधित करता है, और हाँ, आपको उन्हें हर जगह जोड़ना होगा। :(वीएस2012 'एसिंक' का समर्थन करने वाली पहली रिलीज है; उम्मीद है कि हम भविष्य में बेहतर डिबगिंग समर्थन प्राप्त करेंगे! –

+0

आपने अपना दिन बचाया। यह जानकर कि वास्तव में कोई कहां से आया है,^^ डिबगिंग में अंतर डालता है। बग जो मैं खोज रहा हूं दिन लगभग तुरंत स्पष्ट हो गए; यह बहुत बुरा है, मैं आपके नाम का उपयोग किये बिना Google के साथ अपनी ब्लॉग एंट्री नहीं ढूंढ सकता। शायद आप ऑप्टिमाइज़ करना चाहते हैं क्योंकि आपका ब्लॉग अच्छा है और अन्य उपयोगी प्रविष्टियां हैं जो मुझे समय मिलती है । – Patrick

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