2012-09-09 9 views
72

मैं कुछ मैंने सोचा था कि के साथ .NET 4.5भागो दो async कार्यों और .NET में परिणामों को एकत्र 4.5

मैं दो लंबी चलने कार्यों को बंद सक्रिय करना चाहते हैं काम कर आसान होगा प्राप्त करने के लिए कुछ समय के लिए कोशिश कर रहा है एक ही समय में और
परिणाम सबसे अच्छा सी # 4.5 (RTM) जिस तरह से

निम्नलिखित कार्यों में में इकट्ठा लेकिन मैं इसे पसंद नहीं है क्योंकि:

  • मैं Sleep चाहते एक async विधि ऐसा हो यह await ओथ कर सकता है er विधियों
  • यह सिर्फ Task.Run()
  • के साथ बेकार दिखता है मुझे नहीं लगता कि यह किसी भी नई भाषा सुविधाओं का भी उपयोग कर रहा है!

कार्य कोड:

public static void Go() 
{ 
    Console.WriteLine("Starting"); 

    var task1 = Task.Run(() => Sleep(5000));  
    var task2 = Task.Run(() => Sleep(3000)); 

    int totalSlept = task1.Result + task2.Result; 

    Console.WriteLine("Slept for a total of " + totalSlept + " ms"); 
} 

private static int Sleep(int ms) 
{ 
    Console.WriteLine("Sleeping for " + ms); 
    Thread.Sleep(ms); 
    Console.WriteLine("Sleeping for " + ms + " FINISHED"); 
    return ms; 
} 

गैर काम कर कोड:

अद्यतन: यह वास्तव में काम करता है और यह करने के लिए सही तरीका है, समस्या सिर्फ Thread.Sleep है

यह कोड काम नहीं करता है क्योंकि कैल एल से Sleep(5000) तुरंत चलने वाले कार्य को शुरू करता है ताकि Sleep(1000) इसे पूरा होने तक चलाया न जाए। यह सच है भले ही Sleepasync है और मैं await का उपयोग नहीं कर रहा हूं या बहुत जल्द .Result पर कॉल कर रहा हूं।

मैंने सोचा कि शायद वहाँ एक रास्ता पाने के लिए एक गैर चल Task<T> एक async विधि को फोन करके तो मैं फिर दो कार्यों पर Start() कह सकते हैं, लेकिन मैं एक async कॉल करने से एक Task<T> पाने के लिए को समझ नहीं सकता तरीका।

public static void Go() 
{ 
    Console.WriteLine("Starting"); 

    var task1 = Sleep(5000); // blocks 
    var task2 = Sleep(1000); 

    int totalSlept = task1.Result + task2.Result; 

    Console.WriteLine("Slept for " + totalSlept + " ms"); 
} 

private static async Task<int> Sleep(int ms) 
{ 
    Console.WriteLine("Sleeping for " + ms); 
    Thread.Sleep(ms); 
    return ms; 
} 
+0

ध्यान दें: बनाने के लिए जाओ एक async विधि कोई फर्क नहीं –

+3

ब्लॉक 'पर हो रहा है बनाता है task1.Result' 'var task1 = नींद (5000) 'पर नहीं है क्योंकि आपकी स्लीप विधि बिना प्रतीक्षा कीवर्ड है तुल्यकालिक। – Arvis

उत्तर

34

आपको एस्किन प्रोग्रामिंग के लिए स्लीप के बजाय टास्क.डेले का उपयोग करना चाहिए और फिर टास्क का उपयोग करना चाहिए। कार्य परिणामों को गठबंधन करने के लिए सभी। कार्य समानांतर में चलेंगे।

public class Program 
    { 
     static void Main(string[] args) 
     { 
      Go(); 
     } 
     public static void Go() 
     { 
      GoAsync(); 
      Console.ReadLine(); 
     } 
     public static async void GoAsync() 
     { 

      Console.WriteLine("Starting"); 

      var task1 = Sleep(5000); 
      var task2 = Sleep(3000); 

      int[] result = await Task.WhenAll(task1, task2); 

      Console.WriteLine("Slept for a total of " + result.Sum() + " ms"); 

     } 

     private async static Task<int> Sleep(int ms) 
     { 
      Console.WriteLine("Sleeping for {0} at {1}", ms, Environment.TickCount); 
      await Task.Delay(ms); 
      Console.WriteLine("Sleeping for {0} finished at {1}", ms, Environment.TickCount); 
      return ms; 
     } 
    } 
+1

के पक्ष को तोड़ता हूं तो यह काम करता है यह एक अच्छा जवाब है ... लेकिन मैंने सोचा कि जब तक मैं इसे चलाता हूं तो यह गलत जवाब था। तो मैं समझ गया। यह वास्तव में 5 सेकंड में निष्पादित करता है। चाल तुरंत कार्य का इंतजार नहीं कर रही है, बजाय कार्य पर प्रतीक्षा करें। जब भी। –

3

जबकि अपने Sleep विधि async है, Thread.Sleep नहीं है। एसिंक का पूरा विचार एक थ्रेड का पुन: उपयोग करना है, कई धागे शुरू नहीं करना है। क्योंकि आपने थ्रेड पर सिंक्रोनस कॉल का उपयोग करके अवरुद्ध कर दिया है। सो जाओ, यह काम नहीं करेगा।

मुझे लगता है कि Thread.Sleep आप वास्तव में क्या करना चाहते हैं इसका एक सरलीकरण है। क्या आपका वास्तविक कार्यान्वयन एसिंक तरीकों के रूप में कोड किया जा सकता है?

यदि आपको एकाधिक सिंक्रोनस अवरुद्ध कॉल चलाने की आवश्यकता है, तो मुझे लगता है कि कहीं और देखो!

+0

धन्यवाद रिचर्ड - हाँ, ऐसा लगता है कि जब मैं वास्तव में अपनी सेवा कॉल –

+0

का उपयोग करता हूं तो एसिंक कैसे चलाया जाए? मेरे पास ऐसा एप्लिकेशन है जो बहुत से फाइल स्विचिंग करता है और फाइल के लिए इंतजार करता है, लगभग 5 सेकंड, और फिर दूसरी प्रक्रिया, जब मैं "जब सभी के लिए" पहले इसे पहले चलाता हूं, तो दूसरा, भले ही मैंने कहा: 'var x = y() ', और नहीं 'var x = प्रतीक्षा y()' या 'y()। प्रतीक्षा करें()' अभी तक यह अभी भी इंतजार कर रहा है, और यदि async स्वयं को संभाल नहीं रहा है, तो मुझे क्या करना चाहिए? ध्यान दें कि y एसिंक के साथ सजाया गया है, और मैं उम्मीद करता हूं कि यह सब कुछ करने के लिए सही होगा, बिल्कुल सही नहीं है, संपादित करें, संपादित करें: मैं बस अपने साथी से कहता हूं, चलो 'टास्क.फैक्टरी' आज़माएं, और उसने कहा जब मैं इस कक्षा – deadManN

1

इस आलेख ने कई चीजों की व्याख्या करने में मदद की। यह अक्सर पूछे जाने वाले प्रश्न शैली में है।

Async/Await FAQ

इस भाग बताता है कि क्यों एक ही मूल धागे पर Thread.Sleep रन - मेरी प्रारंभिक भ्रम के लिए अग्रणी।

"async" एक प्रणाली के मंगलाचरण ThreadPool करने के लिए क़तार में कारण है? नया धागा बनाने के लिए? मंगल ग्रह पर रॉकेट जहाज लॉन्च करने के लिए?

सं। संख्या और नहीं। पिछले प्रश्न देखें। "Async" कीवर्ड संकलक को इंगित करता है कि विधि के अंदर "प्रतीक्षा" का उपयोग किया जा सकता है, जैसे कि विधि एक प्रतीक्षा बिंदु पर निलंबित हो सकती है और का निष्पादन अवांछित रूप से फिर से शुरू हो गया है जब प्रतीक्षा उदाहरण पूर्ण हो जाता है। यही कारण है कि संकलक एक चेतावनी जारी करता है यदि "async" के रूप में चिह्नित विधि के अंदर "प्रतीक्षा" है।

80
async Task LongTask1() { ... } 
async Task LongTask2() { ... } 
... 
{ 
    Task t1 = LongTask1(); 
    Task t2 = LongTask2(); 
    await Task.WhenAll(t1,t2); 
    //now we have t1.Result and t2.Result 
} 
+1

मैं +1 करता हूं क्योंकि आप टी 1, टी 2 को कार्य के रूप में घोषित करते हैं, जो सही तरीका है। – Minime

+9

मेरा मानना ​​है कि इस समाधान के लिए गो विधि को एसिंक भी होना आवश्यक है, जिसका अर्थ है कि यह असीमित होने की क्षमता का खुलासा करता है। यदि आप पूछताछ के मामले की तरह कुछ और चाहते थे जहां कॉलर की 'गो' विधि तुल्यकालिक है, लेकिन दो स्वतंत्र कार्यों को असीमित रूप से पूरा करना चाहता है (यानी न तो दूसरे के सामने पूरा करने की आवश्यकता है, लेकिन निष्पादन जारी रखने से पहले दोनों को पूरा करना होगा) तो ** कार्य ।WaitAll' ** बेहतर होगा, और आपको प्रतीक्षा कीवर्ड की आवश्यकता नहीं है, इस प्रकार कॉलिंग 'गो' विधि को एसिंक स्वयं होने की आवश्यकता नहीं है। ** न तो दृष्टिकोण बेहतर है, यह सिर्फ आपका लक्ष्य है कि आपका लक्ष्य क्या है। ** – AaronLS

+1

शून्य मेथोड: 'async शून्य LongTask1() {...} 'का कोई कार्य नहीं है। परिणाम संपत्ति। ऐसे मामले में टी के बिना कार्य का उपयोग करें: 'async कार्य LongTask1() '। – Arvis

0

इस बात का जवाब करने के लिए:

मैं तो यह अन्य तरीकों

का इंतजार कर सकते हैं एक async विधि के लिए सो चाहते

आप शायद Sleep समारोह इस तरह पुनर्लेखन कर सकते हैं:

private static async Task<int> Sleep(int ms) 
{ 
    Console.WriteLine("Sleeping for " + ms); 
    var task = Task.Run(() => Thread.Sleep(ms)); 
    await task; 
    Console.WriteLine("Sleeping for " + ms + "END"); 
    return ms; 
} 

static void Main(string[] args) 
{ 
    Console.WriteLine("Starting"); 

    var task1 = Sleep(2000); 
    var task2 = Sleep(1000); 

    int totalSlept = task1.Result +task2.Result; 

    Console.WriteLine("Slept for " + totalSlept + " ms"); 
    Console.ReadKey(); 
} 

इस कोड इच्छा उत्पादन चल रहा है:

Starting 
Sleeping for 2000 
Sleeping for 1000 
*(one second later)* 
Sleeping for 1000END 
*(one second later)* 
Sleeping for 2000END 
Slept for 3000 ms 
1

यह सप्ताह के अंत में अब है!

public static void Go() { 
    Console.WriteLine("Start fosterage...\n"); 
    var t1 = Sleep(5000, "Kevin"); 
    var t2 = Sleep(3000, "Jerry"); 
    var result = Task.WhenAll(t1, t2).Result; 

    Console.WriteLine("\nMy precious spare time last for only {0}ms", result.Max()); 
    Console.WriteLine("Press any key and take same beer..."); 
    Console.ReadKey(); 
} 

private static async Task<int> Sleep(int ms, string n) { 
     Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); 
     await Task.Delay(ms); 
     Console.WriteLine("{0} waked up after {1}ms :(", n, ms); 
     return ms; 
} 

साधारण Task.Factory उदाहरण:

private static Task<int> Sleep(int ms, string n) { 
     return Task.Factory.StartNew(() => { 
      Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); 
      Thread.Sleep(ms); 
      Console.WriteLine("{0} waked up after {1}ms :(", n, ms); 
      return ms; 
     }); 
    } 

रहस्यमय TaskCompletionSource उदाहरण:

private static Task<int> Sleep(int ms, string n) { 
    var tcs = new TaskCompletionSource<int>(); 
    Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); 
    var t = Task.Factory.StartNew(() => { 
     Thread.Sleep(ms); 
     Console.WriteLine("{0} waked up after {1}ms :(", n, ms); 
     tcs.SetResult(ms); 
    }); 
    return tcs.Task; 
} 
संबंधित मुद्दे