টাস্ক.স্টার্ট / ওয়েট এবং এসাইক / অ্যাওয়েটের মধ্যে পার্থক্য কী?


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 ঘন্টা অবরুদ্ধ করে রাখে?
সোভিক

62
@StrugglingCoder: অপেক্ষায় রয়েছেন অপারেটর নেই না ছাড়া কিছু তার প্রতীক মূল্যায়ন এবং তারপর অবিলম্বে বর্তমান কলারের কাছে একটি টাস্ক আসতে । লোকেরা তাদের মাথায় এই ধারণা পেয়ে যায় যে থ্রেডগুলিতে অফলোডিং কাজের মাধ্যমে কেবল অ্যাসিঙ্ক্রোনাই অর্জন করা যেতে পারে, তবে এটি মিথ্যা। টোস্টারটি টোস্টারটি দেখার জন্য কোনও কুককে ভাড়া না দিয়ে টোস্টে থাকাকালীন আপনি প্রাতঃরাশ রান্না করতে পারেন এবং কাগজটি পড়তে পারেন। লোকেরা বলে যে ভাল, টোস্টারের অভ্যন্তরে লুকিয়ে থাকা একজন কর্মী - একটি শ্রমিক অবশ্যই থাকবে, তবে আমি আপনাকে আশ্বাস দিচ্ছি যে আপনি যদি নিজের টোস্টারের দিকে তাকান তবে সেখানে টোস্টটি দেখার কোনও ছোট লোক নেই।
এরিক লিপার্ট

11
@ স্ট্রাগলিংকডার: সুতরাং, আপনি যে কাজটি জিজ্ঞাসা করছেন সে কাজটি কে করছে? হতে পারে অন্য থ্রেডটি কাজ করছে, এবং সেই থ্রেডটি একটি সিপিইউতে দেওয়া হয়েছে, সুতরাং কাজটি আসলেই করা হচ্ছে। সম্ভবত কাজটি হার্ডওয়্যার দ্বারা চলছে এবং কোনও থ্রেড নেই। তবে অবশ্যই, আপনি বলেছেন, হার্ডওয়্যারটিতে কিছু থ্রেড থাকা আবশ্যক । নং হার্ডওয়্যার থ্রেডের স্তরের নীচে বিদ্যমান। কোন সুতোর দরকার নেই! স্টিফেন ক্লিয়ারির আর্টিকেল নেই বলে কোনও লেখা পড়ে আপনি উপকৃত হতে পারেন।
এরিক লিপার্ট

6
@ স্ট্রাগলিংকডার: এখন, প্রশ্ন করুন, ধরুন এখানে অ্যাসিক্রোনাস কাজ চলছে এবং কোনও হার্ডওয়্যার নেই, এবং অন্য কোনও থ্রেড নেই। এটা কিভাবে সম্ভব? ঠিক আছে, ধরুন আপনি যে বিষয়টির অপেক্ষায় ছিলেন সেগুলি উইন্ডোজ বার্তাগুলির একটি ধারাবাহিকভাবে সারি রেখেছে , যার প্রতিটিটিতে কিছুটা কাজ করা যায়? এখন কি হয়? আপনি বার্তা লুপটিতে নিয়ন্ত্রণ ফিরিয়ে আনুন, এটি বার্তাটিকে সারিবদ্ধ করা থেকে শুরু করে প্রতিবার কিছুটা কাজ শুরু করে এবং শেষ কাজটি হ'ল "টাস্কের ধারাবাহিকতা সম্পাদন"। কোনও অতিরিক্ত থ্রেড নেই!
এরিক লিপার্ট

8
@ স্ট্রাগলিংকোডার: এখন, আমি কী বলেছিলাম তা ভেবে দেখুন। আপনি ইতিমধ্যে জানেন যে উইন্ডোজ এভাবেই কাজ করে । আপনি মাউস আন্দোলন এবং বোতাম ক্লিকগুলি এবং হোয়াট নোটের একটি সিরিজ সম্পাদন করেন। বার্তাগুলি সারিবদ্ধ করা হয়, পরিবর্তে প্রক্রিয়াজাত করা হয়, প্রতিটি বার্তা একটি ক্ষুদ্র পরিমাণে কাজ করার কারণ হয়ে থাকে এবং এটি সমস্ত শেষ হয়ে গেলে, সিস্টেম চলতে থাকে। এক থ্রেডে অ্যাসিঙ্ক আপনার ইতিমধ্যে ব্যবহার করা ব্যতীত আর কিছুই নয়: বড় কাজগুলিকে সামান্য বিটগুলিতে বিভক্ত করা, তাদের সারি সারি করা এবং কিছুটা ছোট ক্রমকে কিছু ক্রমে কার্যকর করা। এই মৃত্যুদণ্ড কার্যকর করা কারও কারও কারণে অন্য কাজ সারিবদ্ধ হয়ে যায় এবং জীবন চলতে থাকে। এক সুতো!
এরিক লিপার্ট

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

এই উদাহরণটি পার্থক্যটি খুব স্পষ্টভাবে প্রদর্শন করে। অ্যাসিঙ্ক / অপেক্ষার সাথে কলিং থ্রেড ব্লক হবে না এবং চালানো চালিয়ে যাবে না।

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);
}

দো-টাস্ক আউটপুট:

[1] প্রোগ্রাম শুরু
[1] 1 - শুরু হচ্ছে
[1] 2 - কার্য শুরু হয়েছে
[3] এ - কিছু শুরু করেছেন
[3] খ - কিছু সম্পন্ন হয়েছে
[1] 3 - ফলাফলের সাথে টাস্ক শেষ হয়েছে: 123
[1] প্রোগ্রামের সমাপ্তি

DoAsAncnc আউটপুট:

[1] প্রোগ্রাম শুরু
[1] 1 - শুরু হচ্ছে
[1] 2 - কার্য শুরু হয়েছে
[3] এ - কিছু শুরু করেছেন
[1] প্রোগ্রামের সমাপ্তি
[3] খ - কিছু সম্পন্ন হয়েছে
[3] 3 - ফলাফলের সাথে টাস্ক শেষ হয়েছে: 123

আপডেট: আউটপুটে থ্রেড আইডি দেখিয়ে উন্নত উদাহরণ।


4
তবে আমি যদি করি: নতুন টাস্ক (ডোএএসটাস্ক) St স্টার্ট (); DoAsAsync () এর পরিবর্তে; আমি একই কার্যকারিতা
পেয়েছি

1
আপনার প্রস্তাবের সাথে, কাজের ফলাফলটি অন্য কোথাও মূল্যায়ন করতে হবে, অন্য কোনও পদ্ধতি বা ল্যাম্বডা হতে পারে। অ্যাসিঙ্ক-প্রতীক্ষা অ্যাসিঙ্ক্রোনাস কোড অনুসরণ করা সহজ করে তোলে। এটি কেবল একটি বাক্য গঠন বর্ধক।
মাস

@ যেহেতু প্রোগ্রামের সমাপ্তি এ-এর পরে কেন হয় তা আমি পাই না something আমার বোঝাপড়া থেকে যখন কীওয়ার্ড প্রক্রিয়াটির অপেক্ষার বিষয়টি আসে তখনই তাত্ক্ষণিকভাবে মূল প্রসঙ্গে যেতে হবে এবং তারপরে ফিরে যেতে হবে।

@ জিমি জিম আমার বুঝতে টাস্ক.ফ্যাক্টরি.স্টার্টনিউ থেকে ডসোমিংথিংটটেকটাইম চালানোর জন্য একটি নতুন থ্রেড স্পিন করবে। এর মতো প্রোগ্রামের সমাপ্তি বা এ - শুরু করা কিছু আগে কার্যকর করা হবে কিনা তার কোনও গ্যারান্টি নেই।
রিয়ানডিপি

@ জিমি জিম: থ্রেড আইডিগুলি দেখানোর জন্য আমি নমুনাটি আপডেট করেছি। আপনি দেখতে পাচ্ছেন, "প্রোগ্রাম শেষ" এবং "এ - শুরু করা কিছু" বিভিন্ন থ্রেডে চলছে। সুতরাং আসলে আদেশটি নির্বিচারক নয়।
মাস

10

অপেক্ষা করুন (), সিঙ্ক পদ্ধতিতে সম্ভাব্য async কোড চালাবে run অপেক্ষা করবেন না।

উদাহরণস্বরূপ, আপনার কাছে একটি এসপ নেট ওয়েব অ্যাপ্লিকেশন রয়েছে। ইউজারএ কল / গেট ইউজার / 1 টি শেষ পয়েন্ট। এসপ নেট অ্যাপ্লিকেশন পুল থ্রেড পুল (থ্রেড 1) থেকে একটি থ্রেড চয়ন করবে এবং, এই থ্রেডটি একটি কল কল করবে। আপনি যদি অপেক্ষা করুন () করেন তবে এই থ্রেডটি এইচপি কল কল সমাধান না হওয়া অবধি অবরুদ্ধ থাকবে। এটি অপেক্ষা করার সময়, যদি ইউজারবি কল / গেটউজার / 2 কল করে, তবে, অ্যাপ পুলটিতে আবার এইচপি কল করার জন্য অন্য থ্রেড (থ্রেডড 2) পরিবেশন করতে হবে। আপনি স্রেফ তৈরি করেছেন (ভাল, আসলে অ্যাপ পুল থেকে আনা হয়েছে) অকারণে অন্য থ্রেড তৈরি করেছেন, কারণ আপনি থ্রেডড 1 ব্যবহার করতে পারবেন না এটি ওয়েট () দ্বারা অবরুদ্ধ ছিল।

আপনি যদি থ্রেডড 1 এ অপেক্ষা করতে থাকেন, তবে, সিঙ্ককন্টেক্সটি থ্রেড 1 এবং HTTP কলের মধ্যে সিঙ্ক পরিচালনা করবে। কেবলমাত্র, একবার কল করার পরে এটি অবহিত হবে। এদিকে, যদি ইউজারবি কল / গেটউজার / 2 কল করে তবে আপনি আবার থ্রিড 1 ব্যবহার করতে এইচটিসি কল করতে পারবেন কারণ এটি হিট হওয়ার অপেক্ষা করে একবার প্রকাশিত হয়েছিল। তারপরে আর একটি অনুরোধ এটি আরও বেশি ব্যবহার করতে পারে। একবার HTTP কল হয়ে গেলে (ইউজার 1 বা ইউজার 2), থ্রেড 1 ফলাফল পেতে এবং কলার (ক্লায়েন্ট) এ ফিরে আসতে পারে। থ্রেড 1 একাধিক কাজের জন্য ব্যবহৃত হয়েছিল।


9

এই উদাহরণে, ব্যবহারিকভাবে খুব বেশি নয়। আপনি যদি এমন কোনও টাস্কের অপেক্ষায় থাকেন যা কোনও ভিন্ন থ্রেডে ফিরে আসে (যেমন একটি ডাব্লুসিএফ কল) বা অপারেটিং সিস্টেমের নিয়ন্ত্রণ ছেড়ে দেয় (ফাইল আইও এর মতো), অপেক্ষা করুন কোনও থ্রেড ব্লক না করে কম সিস্টেমের রিসোর্স ব্যবহার করবে।


3

উপরের উদাহরণে, আপনি "TaskCreationOptions.HideScheduler" ব্যবহার করতে পারেন এবং "DoAsTask" পদ্ধতিটি ব্যাপকভাবে পরিবর্তন করতে পারেন। পদ্ধতিটি নিজেই অ্যাসিনক্রোনাস নয়, কারণ এটি "ডোএএএসএএনসিএনসি" এর সাথে ঘটে কারণ এটি একটি "টাস্ক" মান দেয় এবং "অ্যাসিঙ্ক" হিসাবে চিহ্নিত হয়, এটি বেশ কয়েকটি সংমিশ্রণ তৈরি করে, এইভাবে এটি আমাকে "অ্যাসিঙ্ক / অপেক্ষারত" ব্যবহার করার মতোই একই রকম দেয় :

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;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.