2014-04-14 7 views
11

यहाँ एक सरल WinForms अनुप्रयोग है:TaskScheduler.Current के व्यवहार को समझना

using System; 
using System.Diagnostics; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace WindowsFormsApplication 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private async void button1_Click(object sender, EventArgs e) 
     { 
      var ts = TaskScheduler.FromCurrentSynchronizationContext(); 
      await Task.Factory.StartNew(async() => 
      { 
       Debug.WriteLine(new 
       { 
        where = "1) before await", 
        currentTs = TaskScheduler.Current, 
        thread = Thread.CurrentThread.ManagedThreadId, 
        context = SynchronizationContext.Current 
       }); 

       await Task.Yield(); // or await Task.Delay(1) 

       Debug.WriteLine(new 
       { 
        where = "2) after await", 
        currentTs = TaskScheduler.Current, 
        thread = Thread.CurrentThread.ManagedThreadId, 
        context = SynchronizationContext.Current 
       }); 

      }, CancellationToken.None, TaskCreationOptions.None, scheduler: ts).Unwrap(); 
     } 
    } 
} 

डिबग ouput (बटन क्लिक होने): TaskScheduler.Current क्यों है बदल रहा है:

 
{ where = 1) before await, currentTs = System.Threading.Tasks.SynchronizationContextTaskScheduler, thread = 9, context = System.Windows.Forms.WindowsFormsSynchronizationContext } 
{ where = 2) after await, currentTs = System.Threading.Tasks.ThreadPoolTaskScheduler, thread = 9, context = System.Windows.Forms.WindowsFormsSynchronizationContext } 

सवाल SynchronizationContextTaskScheduler से ThreadPoolTaskScheduler से await के बाद यहां?

यह अनिवार्य रूप से व्यवहार TaskCreationOptions.HideSchedulerawait निरंतरता के लिए प्रदर्शित करता है, जो मेरी राय में अप्रत्याशित और अवांछनीय है।

AspNetSynchronizationContext and await continuations in ASP.NET:

यह सवाल मेरा एक और सवाल से शुरू हो रहा किया गया है।

उत्तर

12

यदि कोई वास्तविक कार्य निष्पादित किया जा रहा है, तो TaskScheduler.CurrentTaskScheduler.Default के समान है। दूसरे शब्दों में, ThreadPoolTaskScheduler वास्तव में थ्रेड पूल कार्य शेड्यूलर और दोनों के रूप में कार्य करता है जिसका अर्थ "कोई वर्तमान कार्य शेड्यूलर" नहीं है।

async प्रतिनिधि का पहला भाग स्पष्ट रूप से SynchronizationContextTaskScheduler का उपयोग करके निर्धारित किया गया है, और एक कार्य शेड्यूलर और सिंक्रनाइज़ेशन संदर्भ दोनों के साथ यूआई थ्रेड पर चलता है। कार्य शेड्यूलर प्रतिनिधि को सिंक्रनाइज़ेशन संदर्भ में आगे बढ़ाता है।

जब await इसके संदर्भ को कैप्चर करता है, तो यह सिंक्रनाइज़ेशन संदर्भ (कार्य शेड्यूलर नहीं) को कैप्चर करता है, और उस सिंकक्टिक्स को फिर से शुरू करने के लिए उपयोग करता है। इसलिए, विधि निरंतरता उस सिंकक्टिक्स पर पोस्ट की जाती है, जो इसे UI थ्रेड पर निष्पादित करती है।

जब निरंतरता UI थ्रेड पर चलती है, तो यह एक ईवेंट हैंडलर के समान ही व्यवहार करती है; प्रतिनिधि को सीधे कार्य निष्पादित किया जाता है, एक कार्य में लपेटा नहीं जाता है। यदि आप button1_Click की शुरुआत में TaskScheduler.Current चेक करते हैं, तो आप पाएंगे कि यह ThreadPoolTaskScheduler भी है।

बीटीडब्लू, मैं आपको सलाह देता हूं कि आप इस व्यवहार का व्यवहार करें (कार्यों को सीधे लपेटकर, कार्यों में लपेटा नहीं गया है) एक कार्यान्वयन विस्तार के रूप में।

+0

इस तरह मैंने सोचा कि यह काम करता है लेकिन कुछ और जानकारी के बिना टिप्पणी नहीं करना चाहता था। +1। –

+0

मैं देखता हूं, स्पष्ट रूप से यह है कि 'टास्कवाइटर' कैसे काम करता है। आईएमओ, जो डिजाइन "फ्लोइंग" के लिए आया है, 'टास्कशेड्यूलर। कंटेंट' बल्कि भ्रमित है: आम तौर पर यह नहीं है कि आप तर्कसंगत रूप से यह अपेक्षा करते हैं। – Noseratio

+4

सहमत; 'TaskScheduler.Current' को दिमाग में गतिशील समांतरता के साथ डिजाइन किया गया था, ताकि बाल कार्य शेड्यूलर को उनके मूल कार्यों से प्राप्त कर सकें। यह डिफ़ॉल्ट व्यवहार async कार्यों के लिए भ्रमित है, इसलिए मैं प्रत्येक 'StartNew' और' ContinueWith' में शेड्यूलर को स्पष्ट रूप से निर्दिष्ट करने का आग्रह करता हूं। –

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