2015-07-18 14 views
10

लगभग इस विषय के बारे में हर एसओ का जवाब, कहा गया है कि:async - स्पष्टीकरण?

LINQ doesn't work perfectly with async

इसके अलावा:

I recommend that you not think of this as "using async within LINQ"

लेकिन स्टीफन किताब में वहाँ के लिए एक नमूना है :

समस्या: आप का इंतजार करने के लिए कार्यों की एक संग्रह है, और आप प्रत्येक कार्य पर कुछ प्रसंस्करण करने के लिए यह पूरा करने के बाद चाहते हैं। हालांकि, आप प्रत्येक के लिए प्रसंस्करण के रूप में जल्द ही प्रसंस्करण करना चाहते हैं, अन्य कार्यों में से किसी के लिए प्रतीक्षा कर रहा है।

सिफारिश समाधान में से एक था:

static async Task<int> DelayAndReturnAsync(int val) 
{ 
await Task.Delay(TimeSpan.FromSeconds(val)); 
return val; 
} 

// This method now prints "1", "2", and "3". 
static async Task ProcessTasksAsync() 
{ 
// Create a sequence of tasks. 
Task<int> taskA = DelayAndReturnAsync(2); 
Task<int> taskB = DelayAndReturnAsync(3); 
Task<int> taskC = DelayAndReturnAsync(1); 
var tasks = new[] { taskA, taskB, taskC }; 
var processingTasks = tasks.Select(async t => 
    { 
    var result = await t; 
    Trace.WriteLine(result); 
    }).ToArray(); 

// Await all processing to complete 
await Task.WhenAll(processingTasks); 

} 

प्रश्न # 1:

मुझे समझ नहीं आता क्यों अब async एक LINQ बयान के अंदर - काम करता है। क्या हमने अभी नहीं कहा " LINQ के भीतर async का उपयोग करने के बारे में सोचें"?

प्रश्न # 2: - क्या वास्तव में ऐसा है

जब नियंत्रण यहाँ await t तक पहुँच जाता है? क्या नियंत्रण ProcessTasksAsync विधि छोड़ देता है? या क्या यह अनाम विधि छोड़ देता है और पुनरावृत्ति जारी रखता है?

+0

कि "डॉन इसके बारे में नहीं सोचते ... "कथन अनिवार्य नहीं था। आपके द्वारा उद्धृत ग्रंथों में से कोई भी नहीं कहता है कि एसिंक लिंक के साथ काम नहीं करेगा - बस टोपी यह एकदम सही मैच नहीं है। –

+0

स्टीफन टब द्वारा एक अच्छा पठन, यदि आप अभी तक इसमें नहीं आए हैं: [कार्य, मोनाड्स, और LINQ] (http://blogs.msdn.com/b/pfxteam/archive/2013/04/03/tasks -monads और linq.aspx)। – Noseratio

उत्तर

8

मुझे समझ में नहीं आता कि अब LINQ कथन के अंदर async क्यों काम करता है। क्या हमने अभी नहीं कहा "LINQ के भीतर एसिंक का उपयोग करने के बारे में मत सोचो"?

asyncज्यादातर LINQ साथ काम नहीं करता क्योंकि IEnumerable<T> एक्सटेंशन हमेशा ठीक से प्रतिनिधि प्रकार का अनुमान लगा नहीं है और Action<T> लिए स्थगित। उन्हें Task कक्षा की कोई विशेष समझ नहीं है। इसका मतलब है कि वास्तविक एसिंक प्रतिनिधि async void बन जाता है, जो खराब है। Enumerable.Select के मामले में, हमारे पास एक अधिभार है जो Func<T> (जो बदले में Func<Task> हमारे मामले में होगा), जो async Task के बराबर है, इसलिए यह एसिंक उपयोग-मामलों के लिए ठीक काम करता है।

जब नियंत्रण यहां प्रतीक्षा कर रहा है - वास्तव में क्या होता है? क्या नियंत्रण ProcessTasksAsync विधि को छोड़ देता है?

नहीं, ऐसा नहीं है। Enumerable.Select अनुक्रम में सभी तत्वों को प्रक्षेपित करने के बारे में है।इसका मतलब है कि संग्रह में प्रत्येक तत्व के लिए, await t जो पुनरावर्तक को वापस नियंत्रण प्रदान करेगा, जो सभी तत्वों को पुन: जारी रखेगा। यही कारण है कि बाद में सभी तत्वों ने निष्पादन समाप्त कर दिया है, यह सुनिश्चित करने के लिए कि आपको await Task.WhenAll पर जाना है।

3

प्रश्न 1: Trace.WriteLine(result);:

अंतर प्रत्येक कार्य अतिरिक्त संसाधन जो है साथ जारी रखा है। जिस लिंक पर आपने इंगित किया है, वह कोड कुछ भी नहीं बदलेगा, बस किसी अन्य कार्य के साथ प्रतीक्षा करने और लपेटने के ऊपरी हिस्से को बनाता है।

प्रश्न 2:

नियंत्रण तक पहुँच जाता है इंतजार टी यहाँ - वास्तव में क्या हो रहा है?

यह ProcessTasksAsync के कार्य के परिणाम के लिए इंतजार कर रहा है, तो Trace.WriteLine(result); साथ जारी रखें। हम कह सकते हैं कि जब हमारे पास परिणाम होता है तो नियंत्रण ProcessTasksAsync विधि छोड़ देता है और प्रसंस्करण अभी भी अज्ञात विधि के अंदर है।

अंत में, हम await Task.WhenAll(processingTasks); है जो अतिरिक्त संसाधन (Trace.WriteLine(result);) से पहले जारी लेकिन प्रत्येक कार्य दूसरों के लिए इंतजार नहीं करता क्रियान्वित जारी रखने के लिए पूरा करने के लिए सहित सभी कार्यों के लिए इंतजार करेंगे: Trace.WriteLine(result);