Task.Start / Wait और Async / Await में क्या अंतर है?


206

मुझे कुछ याद आ रहा है लेकिन क्या करने में अंतर है:

public void MyMethod()
{
  Task t = Task.Factory.StartNew(DoSomethingThatTakesTime);
  t.Wait();
  UpdateLabelToSayItsComplete();
}

public async void MyMethod()
{
  var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
  await result;
  UpdateLabelToSayItsComplete();
}

private void DoSomethingThatTakesTime()
{
  Thread.Sleep(10000);
}

जवाबों:


395

मुझे कुछ याद आ रहा है

तुम हो।

क्या कर के बीच अंतर है Task.Waitऔर await task?

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

Task.Waitजब तक कार्य पूरा नहीं हो जाता है, तब तक आप अपने मित्र की उपेक्षा करते हैं जब तक कि कार्य पूरा नहीं हो जाता। awaitसंदेश की कतार में संदेशों को संसाधित करता रहता है, और जब कार्य पूरा हो जाता है, तो यह एक संदेश देता है जो कहता है कि "पिक अप करें कि आपने उस प्रतीक्षा के बाद कहां छोड़ा था"। आप अपने दोस्त से बात करते हैं, और जब बातचीत में ब्रेक आता है तो सूप आता है।


5
@ क्रोनोग नहीं, यह नहीं है। अगर आप Task10 मिनट का इंतज़ार कर रहे हैं तो आप इसे कैसे पसंद करेंगे? वास्तव में Taskआपके धागे पर 10 घंटे का समय लगेगा , इस प्रकार आपको पूरे 10 घंटे तक रोकना होगा।
svick

62
@StrugglingCoder: इंतजार ऑपरेटर नहीं है कर के अलावा कुछ अपने संकार्य का मूल्यांकन और फिर तुरंत वर्तमान फोन करने वाले के लिए कोई कार्य लौटने । लोग अपने सिर में यह विचार प्राप्त करते हैं कि एसिंक्रोनसी केवल थ्रेड्स पर ऑफलोडिंग कार्य के माध्यम से प्राप्त की जा सकती है, लेकिन यह गलत है। आप नाश्ते को पका सकते हैं और पेपर पढ़ सकते हैं, जबकि टोस्टर टोस्टर में है बिना टोस्टर देखने के लिए कुक को काम पर रख सकते हैं। लोग कहते हैं कि अच्छी तरह से, वहाँ एक धागा होना चाहिए - एक कार्यकर्ता - टोस्टर के अंदर छिपा हुआ है, लेकिन मैं आपको विश्वास दिलाता हूं कि यदि आप अपने टोस्टर को देखते हैं, तो टोस्ट देखने में कोई छोटा आदमी नहीं है।
एरिक लिपर्ट

11
@StrugglingCoder: तो, जो आप पूछ रहे काम कर रहा है? शायद एक और धागा काम कर रहा है, और उस धागे को एक सीपीयू को सौंपा गया है, इसलिए काम वास्तव में किया जा रहा है। हो सकता है कि काम हार्डवेयर द्वारा किया जा रहा हो और इसमें कोई धागा न हो। लेकिन निश्चित रूप से, आप कहते हैं, हार्डवेयर में कुछ धागा होना चाहिए । नहीं। हार्डवेयर थ्रेड्स के स्तर से नीचे मौजूद है। कोई धागा नहीं होना चाहिए! आपको स्टीफन क्लीरी के लेख थ्री इज़ नो थ्रेड को पढ़ने से फायदा हो सकता है।
एरिक लिपर्ट

6
@StrugglingCoder: अब, सवाल, मान लीजिए कि अतुल्यकालिक काम किया जा रहा है और कोई हार्डवेयर नहीं है, और कोई अन्य धागा नहीं है। यह कैसे हो सकता है? ठीक है, मान लीजिए जिस चीज का आपको इंतजार है उसने खिड़कियों के संदेशों की एक श्रृंखला को कतार में खड़ा कर दिया है , जिनमें से प्रत्येक एक छोटा सा काम करता है? अब क्या होता है? आप संदेश लूप पर नियंत्रण लौटाते हैं, यह कतार से संदेशों को खींचना शुरू कर देता है, हर बार थोड़ा सा काम करता है, और जो आखिरी काम किया जाता है वह है "कार्य की निरंतरता को निष्पादित करना"। कोई अतिरिक्त धागा नहीं!
एरिक लिपर्ट

8
@StrugglingCoder: अब, इस बारे में सोचें कि मैंने अभी क्या कहा। आप पहले से ही जानते हैं कि यह विंडोज कैसे काम करता है । आप माउस आंदोलनों और बटन क्लिक और व्हाट्सएप की एक श्रृंखला निष्पादित करते हैं। संदेशों को कतारबद्ध किया जाता है, बदले में संसाधित किया जाता है, प्रत्येक संदेश काम करने की एक छोटी राशि का कारण बनता है, और जब यह सब किया जाता है, तो सिस्टम चालू रहता है। एक थ्रेड पर Async आपके द्वारा पहले से उपयोग किए जाने वाले से अधिक कुछ नहीं है: बड़े कार्यों को छोटे बिट्स में तोड़ना, उन्हें कतारबद्ध करना और कुछ क्रम में सभी छोटे बिट्स को निष्पादित करना। उन निष्पादन में से कुछ के कारण अन्य कार्य कतारबद्ध हो जाते हैं, और जीवन चलता रहता है। एक धागा!
एरिक लिपर्ट

121

एरिक के जवाब को प्रदर्शित करने के लिए यहां कुछ कोड दिए गए हैं:

public void ButtonClick(object sender, EventArgs e)
{
  Task t = new Task.Factory.StartNew(DoSomethingThatTakesTime);
  t.Wait();  
  //If you press Button2 now you won't see anything in the console 
  //until this task is complete and then the label will be updated!
  UpdateLabelToSayItsComplete();
}

public async void ButtonClick(object sender, EventArgs e)
{
  var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
  await result;
  //If you press Button2 now you will see stuff in the console and 
  //when the long method returns it will update the label!
  UpdateLabelToSayItsComplete();
}

public void Button_2_Click(object sender, EventArgs e)
{
  Console.WriteLine("Button 2 Clicked");
}

private void DoSomethingThatTakesTime()
{
  Thread.Sleep(10000);
}

27
कोड के लिए +1 (सौ बार पढ़ने की तुलना में एक बार चलाना बेहतर है)। लेकिन वाक्यांश " //If you press Button2 now you won't see anything in the console until this task is complete and then the label will be updated!" भ्रामक है। जीयूआई के जमे हुए और अनुत्तरदायी होने के बाद से t.Wait();बटन पर क्लिक करने वाले इवेंट हैंडलर में बटन दबाने पर ButtonClick()कुछ भी दबाना संभव नहीं है और फिर "जब तक यह कार्य पूरा नहीं होता है" तब तक कंसोल और लेबल के अपडेट में कुछ न देखें। किया जा रहा है खो कार्य प्रतीक्षा के पूरा होने तक
गेनाडी Vanin Геннадий Ванин

2
मुझे लगता है कि एरिक मानता है कि आपको टास्क आपी की बुनियादी समझ है। मैं उस कोड को देखता हूं और अपने आप से कहता हूं " t.Waitजब तक कार्य पूरा नहीं हो जाता है तब तक यूप मुख्य धागे पर ब्लॉक होने वाला है।"
मफिन मैन

50

यह उदाहरण बहुत स्पष्ट रूप से अंतर प्रदर्शित करता है। Async / प्रतीक्षा के साथ कॉलिंग थ्रेड ब्लॉक नहीं होगा और निष्पादित करना जारी रखेगा।

static void Main(string[] args)
{
    WriteOutput("Program Begin");
    // DoAsTask();
    DoAsAsync();
    WriteOutput("Program End");
    Console.ReadLine();
}

static void DoAsTask()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
    WriteOutput("2 - Task started");
    t.Wait();
    WriteOutput("3 - Task completed with result: " + t.Result);
}

static async Task DoAsAsync()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
    WriteOutput("2 - Task started");
    var result = await t;
    WriteOutput("3 - Task completed with result: " + result);
}

static int DoSomethingThatTakesTime()
{
    WriteOutput("A - Started something");
    Thread.Sleep(1000);
    WriteOutput("B - Completed something");
    return 123;
}

static void WriteOutput(string message)
{
    Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, message);
}

DoAsTask आउटपुट:

[१] कार्यक्रम शुरू
[१] १ - शुरू करना
[१] २ - टास्क शुरू हुआ
[३] ए - कुछ शुरू किया
[३] बी - कुछ पूरा हुआ
[१] ३ - परिणाम के साथ कार्य पूरा हुआ: १२३
[१] प्रोग्राम की समाप्ति

DoAsAsync आउटपुट:

[१] कार्यक्रम शुरू
[१] १ - शुरू करना
[१] २ - टास्क शुरू हुआ
[३] ए - कुछ शुरू किया
[१] प्रोग्राम की समाप्ति
[३] बी - कुछ पूरा हुआ
[३] ३ - परिणाम के साथ कार्य पूरा हुआ: १२३

अपडेट: आउटपुट में थ्रेड आईडी दिखाकर बेहतर उदाहरण।


4
लेकिन अगर मैं करता हूँ: नए कार्य (DoAsTask) .Start (); DoAsAsync () के बजाय; मुझे वही फंक्शनलिटी मिलती है, इसलिए
वेट

1
आपके प्रस्ताव के साथ, कार्य के परिणाम का मूल्यांकन कहीं और किया जाना चाहिए, शायद दूसरी विधि या लंबोदर। एसिंक्श-वेट असिंक्रोनस कोड को फॉलो करना आसान बनाता है। यह सिर्फ एक वाक्यविन्यास बढ़ाने वाला है।
मास

@Mas मुझे नहीं मिलता है कि ए के बाद प्रोग्राम एंड क्यों है - कुछ शुरू किया। मेरी समझ से जब यह प्रतीक्षा करने की बात आती है कि कीवर्ड प्रक्रिया को तुरंत मुख्य संदर्भ में जाना चाहिए और फिर वापस जाना चाहिए।

@JimmyJimm मेरी समझ से Task.Factory.StartNew DoSomethingThatTakesTime को चलाने के लिए एक नया धागा तैयार करेगा। जैसे कि इस बात की कोई गारंटी नहीं है कि प्रोग्राम एंड या ए - स्टार्टेड समथिंग को पहले निष्पादित किया जाएगा या नहीं।
रियाँदप।

@ जिमीजिम: मैंने थ्रेड आईडी दिखाने के लिए नमूना अपडेट किया है। जैसा कि आप देख सकते हैं, "प्रोग्राम एंड" और "ए - स्टार्टेड समथिंग" विभिन्न थ्रेड्स पर चल रहे हैं। तो वास्तव में आदेश निर्धारक नहीं है।
मास

10

प्रतीक्षा करें (), सिंक कोड में संभावित async कोड चलाने का कारण होगा। इंतजार नहीं होगा

उदाहरण के लिए, आपके पास एक asp.net वेब अनुप्रयोग है। UserA कॉल / getUser / 1 समापन बिंदु। asp.net ऐप पूल थ्रेड पूल (थ्रेड 1) से एक थ्रेड उठाएगा और, यह थ्रेड http कॉल करेगा। यदि आप प्रतीक्षा () करते हैं, तो यह धागा तब तक अवरुद्ध रहेगा जब तक http कॉल हल नहीं हो जाती। यदि यह प्रतीक्षा कर रहा है, अगर UserB कॉल / getUser / 2 करता है, तो, ऐप पूल को फिर से http कॉल करने के लिए एक और धागा (Thread2) परोसना होगा। आपने बिना किसी कारण के वास्तव में बनाया (ठीक है, ऐप पूल से प्राप्त किया गया), क्योंकि आप थ्रेड 1 का उपयोग नहीं कर सकते हैं, इसे प्रतीक्षा () द्वारा अवरुद्ध किया गया था।

यदि आप थ्रेड 1 पर प्रतीक्षा का उपयोग करते हैं, तो, SyncContext थ्रेड 1 और http कॉल के बीच सिंक का प्रबंधन करेगा। बस, http कॉल हो जाने के बाद यह सूचित करेगा। इस बीच, अगर उपयोगकर्ता कॉल / गेटअप / 2 करता है, तो, आप HTTP कॉल करने के लिए फिर से थ्रेड 1 का उपयोग करेंगे, क्योंकि यह हिट होने के बाद रिलीज़ किया गया था। फिर एक अन्य अनुरोध इसका उपयोग कर सकता है, और भी अधिक। एक बार http कॉल (user1 या user2) हो जाने के बाद, Thread1 परिणाम प्राप्त कर सकता है और कॉलर (क्लाइंट) को वापस कर सकता है। Thread1 का उपयोग कई कार्यों के लिए किया गया था।


9

इस उदाहरण में, अधिक नहीं, व्यावहारिक रूप से। यदि आप एक टास्क का इंतजार कर रहे हैं जो एक अलग थ्रेड (जैसे WCF कॉल) पर लौटता है या ऑपरेटिंग सिस्टम (जैसे फ़ाइल IO) पर नियंत्रण को छोड़ देता है, तो थ्रेड को ब्लॉक न करके कम सिस्टम संसाधनों का उपयोग करेगा।


3

ऊपर दिए गए उदाहरण में, आप "TaskCreationOptions.HideScheduler" का उपयोग कर सकते हैं, और "DoAsTask" विधि को संशोधित कर सकते हैं। यह विधि अपने आप में अतुल्यकालिक नहीं है, जैसा कि "DoAsAsync" के साथ होता है क्योंकि यह "टास्क" मान लौटाता है और इसे "async" के रूप में चिह्नित किया जाता है, कई संयोजन बनाते हैं, यह है कि यह मुझे "async" का उपयोग करने के समान ही देता है। :

static Task DoAsTask()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime, TaskCreationOptions.HideScheduler); //<-- HideScheduler do the magic

    TaskCompletionSource<int> tsc = new TaskCompletionSource<int>();
    t.ContinueWith(tsk => tsc.TrySetResult(tsk.Result)); //<-- Set the result to the created Task

    WriteOutput("2 - Task started");

    tsc.Task.ContinueWith(tsk => WriteOutput("3 - Task completed with result: " + tsk.Result)); //<-- Complete the Task
    return tsc.Task;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.