async / প্রতীক্ষা - কখন কোন কার্য বনাম বাতিল?


502

কোন পরিস্থিতিতে কোনটি ব্যবহার করতে চাইবে Under

public async Task AsyncMethod(int num)

পরিবর্তে

public async void AsyncMethod(int num)

কেবলমাত্র আমি যে দৃশ্যের কথা ভাবতে পারি তা হ'ল যদি আপনার কাজটির অগ্রগতি ট্র্যাক করতে সক্ষম হয়।

অতিরিক্তভাবে, নিম্নলিখিত পদ্ধতিতে, অ্যাসিঙ্ক এবং কীওয়ার্ডগুলি অপ্রয়োজনীয়?

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}

20
নোট করুন যে async পদ্ধতিগুলি সর্বদা Async নামের সাথে প্রত্যয়যুক্ত হওয়া উচিত x উদাহরণটি Foo()হয়ে উঠবে FooAsync()
ফ্রেড

30
@ ফ্রেড বেশিরভাগ ক্ষেত্রে, তবে সবসময় না। এটি কেবল কনভেনশন এবং এই কনভেনশনের স্বীকৃত ব্যতিক্রম ইভেন্ট ভিত্তিক ক্লাস বা ইন্টারফেস চুক্তি সহ, এমএসডিএন দেখুন । উদাহরণস্বরূপ, আপনার সাধারণ ইভেন্ট হ্যান্ডলারগুলির নাম পরিবর্তন করা উচিত নয়, যেমন বাটন 1_ক্লিক।
বেন

14
পরিবর্তে Thread.Sleepআপনার কাজের সাথে আপনার ব্যবহার করা উচিত নয় কেবল একটি নোটawait Task.Delay(num)
বব ভ্যালে

45
@ ফ্রেড আমি এটির সাথে একমত নই, আপনি যখন সিঙ্ক এবং অ্যাসিঙ্ক উভয় বিকল্পের সাথে ইন্টারফেস সরবরাহ করছেন তখন অ্যাসিঙ্ক প্রত্যয় যুক্ত আইএমও ব্যবহার করা উচিত। স্মুরফ যখন এসাইঙ্কের সাথে জিনিসগুলির নামকরণের একমাত্র উদ্দেশ্য থাকে তখন অর্থহীন। বিন্দু ক্ষেত্রে Task.Delayনয় Task.AsyncDelayএসিঙ্ক সকল যেমন কাজের উপর পদ্ধতি
না প্রিয়জনের

11
আজ সকালে ওয়েবপিপি 2 কন্ট্রোলার পদ্ধতিতে আমার একটি আকর্ষণীয় সমস্যা হয়েছিল, এটি async voidপরিবর্তে ঘোষণা করা হয়েছিল async Task। পদ্ধতিটি ক্র্যাশ হয়ে গেছে কারণ এটি নিয়ন্ত্রকের সদস্য হিসাবে ঘোষিত একটি সত্তা ফ্রেমওয়ার্ক প্রসঙ্গটি অবজেক্টটি ব্যবহার করে পদ্ধতিটি কার্যকর করা শেষ হওয়ার আগেই নিষ্পত্তি করা হয়েছিল। কাঠামোটি কার্যকর করার আগে পদ্ধতিটি শেষ করার আগে নিয়ামককে নিষ্পত্তি করে। আমি পদ্ধতিটি async Task এ পরিবর্তন করেছি এবং এটি কার্যকর হয়েছে।
কস্টা

উত্তর:


417

1) সাধারণত, আপনি ফিরে আসতে চান Task। প্রধান ব্যতিক্রম হওয়া উচিত যখন আপনি প্রয়োজন একটি আছে void(ইভেন্টের জন্য) রিটার্ন টাইপ। যদি কলারটিকে awaitআপনার কাজটি করা থেকে বঞ্চিত করার কোনও কারণ না থাকে তবে কেন তা অস্বীকার করবেন?

2) asyncযে পদ্ধতিগুলি ফিরে আসে voidসেগুলি অন্য দিকটিতে বিশেষ: এগুলি শীর্ষ স্তরের অ্যাসিঙ্ক ক্রিয়াকলাপগুলিকে উপস্থাপন করে এবং আপনার কাজটি যখন কোনও ব্যতিক্রম ফিরিয়ে দেয় তখন অতিরিক্ত নিয়মগুলি কার্যকর হয়। পার্থক্যটি দেখানোর সহজ উপায়টি একটি উদাহরণ সহ:

static async void f()
{
    await h();
}

static async Task g()
{
    await h();
}

static async Task h()
{
    throw new NotImplementedException();
}

private void button1_Click(object sender, EventArgs e)
{
    f();
}

private void button2_Click(object sender, EventArgs e)
{
    g();
}

private void button3_Click(object sender, EventArgs e)
{
    GC.Collect();
}

fএর ব্যতিক্রম সর্বদা "পালন" হয়। একটি ব্যতিক্রম যা শীর্ষ-স্তরের অ্যাসিনক্রোনাস পদ্ধতি ছেড়ে যায় কেবল অন্য যেকোন অপ্রয়োজনীয় ব্যতিক্রমের মতোই আচরণ করা হয়। gএর ব্যতিক্রম কখনই পালন করা হয় না। আবর্জনা সংগ্রহকারী যখন টাস্কটি পরিষ্কার করতে আসে, তখন এটি দেখতে পায় যে কার্যটি একটি ব্যতিক্রম ঘটেছে এবং ব্যতিক্রম কেউই পরিচালনা করেনি। যখন এটি হয়, TaskScheduler.UnobservedTaskExceptionহ্যান্ডলার চালিত হয়। আপনার কখনই এটি হতে দেওয়া উচিত নয়। আপনার উদাহরণ ব্যবহার করতে,

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}

হ্যাঁ, ব্যবহার করুন asyncএবং awaitএখানে, তারা নিশ্চিত হন যে কোনও ব্যতিক্রম ছোঁড়া হলে আপনার পদ্ধতিটি এখনও সঠিকভাবে কাজ করে।

আরও তথ্যের জন্য দেখুন: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx


10
আমি আমার মন্তব্যের fপরিবর্তে বুঝিয়েছি g। থেকে ব্যতিক্রম fপাস হয় SynchronizationContextgউত্থাপন করবে UnobservedTaskException, কিন্তু UTEপ্রক্রিয়াটি পরিচালনা না করা হলে আর ক্র্যাশ করবে না। কিছু পরিস্থিতি রয়েছে যেখানে উপেক্ষা করা এই জাতীয় "অ্যাসিনক্রোনাস ব্যতিক্রমগুলি" গ্রহণযোগ্য।
স্টিফেন ক্লিয়ারি

3
যদি আপনার WhenAnyএকাধিক Taskগুলি থাকে তবে এর ব্যতিক্রম ঘটে। আপনাকে প্রায়শই কেবল প্রথমটিকে পরিচালনা করতে হয় এবং আপনি প্রায়শই অন্যকে উপেক্ষা করতে চান।
স্টিফেন ক্লিয়ারি

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

10
আপনি কেন শূন্যতার পরিবর্তে কোনও টাস্ক ফিরিয়ে দেওয়ার পরামর্শ দিচ্ছেন তা নিয়ে আমি কিছুটা বিভ্রান্ত। যেমনটি আপনি বলেছেন, চ () নিক্ষেপ করবে এবং ব্যতিক্রম করবে কিন্তু জি () তা করবে না। এই পটভূমি থ্রেড ব্যতিক্রম সম্পর্কে সচেতন করা ভাল নয়?
ব্যবহারকারী981225

2
@ ইউজার ৯৮১২২২২ আসলে, তবে তারপরে জি-র কলারের দায়িত্ব হয়ে যায়: জি-কে ডাকার প্রতিটি পদ্ধতিই অ্যাসিঙ্ক হওয়া উচিত এবং অপেক্ষাও করা উচিত। এটি একটি গাইডলাইন, কোনও কঠোর নিয়ম নয়, আপনি সিদ্ধান্ত নিতে পারেন যে আপনার নির্দিষ্ট প্রোগ্রামে জি রিটার্ন শূন্য রাখা আরও সহজ।

40

আমি জেরেম লাবান সম্পর্কে রচনা asyncএবং voidরচনা সম্পর্কে এই খুব দরকারী নিবন্ধটি পেয়েছি : https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void .html

তল লাইনটি হ'ল একটি async+voidসিস্টেম ক্র্যাশ করতে পারে এবং সাধারণত কেবলমাত্র ইউআই পার্শ্ব ইভেন্ট হ্যান্ডলারে ব্যবহার করা উচিত।

এর পিছনে কারণ হ'ল অ্যাসিঙ্কভয়েডমেথডবিল্ডার দ্বারা ব্যবহৃত সিঙ্ক্রোনাইজেশন কনটেক্সট, উদাহরণটিতে আর কোনও নয়। যখন কোনও অ্যাম্বিয়েন্ট সিঙ্ক্রোনাইজেশন প্রসঙ্গ নেই, কোনও অ্যাসিঙ্ক শূন্য পদ্ধতির শৃঙ্খলাবদ্ধ না হওয়া যে কোনও ব্যতিক্রম থ্রেডপুলে পুনরায় উত্সাহিত হয়। যদিও এমন কোনও যৌক্তিক জায়গা নেই যেখানে এই ধরণের অপ্রত্যাশিত ব্যতিক্রম ছোঁড়া যায়, দুর্ভাগ্যজনক প্রভাবটি হ'ল প্রক্রিয়াটি সমাপ্ত হচ্ছে, কারণ থ্রেডপুলে আনহ্যান্ডেল ব্যতিক্রমগুলি কার্যকরভাবে .NET 2.0 থেকে প্রক্রিয়াটি বন্ধ করে দেয়। আপনি অ্যাপডোমাইন.অনহানডেলড এক্সসেপশন ইভেন্টটি ব্যবহার করে সমস্ত অপ্রচলিত ব্যতিক্রমটি আটকাতে পারেন, তবে এই ইভেন্ট থেকে প্রক্রিয়াটি পুনরুদ্ধারের কোনও উপায় নেই।

ইউআই ইভেন্ট হ্যান্ডলারগুলি লেখার সময়, অ্যাসিঙ্ক শূন্য পদ্ধতিগুলি একরকম বেদনাদায়ক কারণ ব্যতিক্রমগুলি অ-অ্যাসিঙ্ক পদ্ধতিতে একইভাবে দেখা হয়; তারা প্রেরণকারী উপর নিক্ষিপ্ত হয়। এই ধরনের ব্যতিক্রমগুলি থেকে পুনরুদ্ধার করার সম্ভাবনা রয়েছে, বেশিরভাগ ক্ষেত্রেই সঠিক থেকে বেশি। ইউআই ইভেন্ট হ্যান্ডলারের বাইরে অবশ্য, অ্যাসিঙ্ক শূন্য পদ্ধতিগুলি কোনওভাবে ব্যবহার করা বিপজ্জনক এবং এটি খুঁজে পাওয়া সহজ নয়।


এটা কি ঠিক? আমি ভেবেছিলাম async পদ্ধতিতে ব্যতিক্রমগুলি টাস্কের মধ্যে ক্যাপচার করা হয়েছে। এবং আফাইক সর্বদা একটি ডিফল্ট সিঙ্ক্রোনাইজেশন কনটেক্সট
এনএম

30

আমি এই বিবৃতি থেকে পরিষ্কার ধারণা পেয়েছি।

  1. অ্যাসিঙ্ক শূন্য পদ্ধতিতে ত্রুটি-হ্যান্ডলিং বিভিন্ন শব্দার্থবিজ্ঞান রয়েছে। যখন একটি ব্যতিক্রম কোনও এসিঙ্ক টাস্ক বা অ্যাসিঙ্ক টাস্ক পদ্ধতি থেকে ছিটকে যায়, তখন সেই ব্যতিক্রমটি টাস্ক অবজেক্টে ক্যাপচার এবং স্থাপন করা হয়। অ্যাসিঙ্ক অকার্যকর পদ্ধতিতে, কোনও টাস্ক অবজেক্ট নেই, সুতরাং একটি অ্যাসিঙ্ক শূন্য পদ্ধতিতে ফেলে দেওয়া ব্যতিক্রমগুলি সরাসরি সিঙ্ক্রোনাইজেশন কনটেক্সট-এ উত্থাপিত হবে (সিঙ্ক্রোনাইজেশন কনটেক্সট এমন একটি অবস্থানের প্রতিনিধিত্ব করে যেখানে "কোড কার্যকর করা হতে পারে।) যা অ্যাসিঙ্ক শূন্য পদ্ধতিতে সক্রিয় ছিল was শুরু

একটি অ্যাসিঙ্ক অকার্যকর পদ্ধতি থেকে ব্যতিক্রম ধরা যায় না

private async void ThrowExceptionAsync()
{
  throw new InvalidOperationException();
}
public void AsyncVoidExceptions_CannotBeCaughtByCatch()
{
  try
  {
    ThrowExceptionAsync();
  }
  catch (Exception)
  {
    // The exception is never caught here!
    throw;
  }
}

এই ব্যতিক্রমগুলি অ্যাপডোমাইন ব্যবহার করে লক্ষ্য করা যায় U GUI / ASP.NET অ্যাপ্লিকেশনগুলির জন্য অনাদৃত এক্সেক্সপশন বা অনুরূপ ক্যাচ-অল ইভেন্ট, তবে নিয়মিত ব্যতিক্রম হ্যান্ডলিংয়ের জন্য এই ইভেন্টগুলি ব্যবহার করা অনিচ্ছাকরণের একটি রেসিপি (এটি অ্যাপ্লিকেশনটিকে ক্র্যাশ করে)।

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

  2. সিঙ্ক্রোনাস ইভেন্ট হ্যান্ডলারটি ব্যবহার করার সময় অ্যাসিঙ্ক ভয়েড পদ্ধতি কার্যকর কারণ তারা সরাসরি তাদের সিঙ্ক্রোনাইজেশন কনটেক্সটগুলিতে ব্যতিক্রমগুলি উত্থাপন করে যা সিঙ্ক্রোনাস ইভেন্ট হ্যান্ডলারদের আচরণের সাথে সমান is

আরও তথ্যের জন্য এই লিঙ্কটি https://msdn.microsoft.com/en-us/magazine/jj991977.aspx দেখুন


21

অ্যাসিঙ্ককে অকার্যকর বলার সমস্যাটি হ'ল আপনি এমনকি টাস্কটি ফিরে পান না, ফাংশনের কাজটি কখন শেষ হয়েছে তা জানার আপনার কোনও উপায় নেই (দেখুন https://blogs.msdn.microsoft.com/oldnewthing/20170720-00/ ? পি = 96655 )

অ্যাসিঙ্ক ফাংশনটি কল করার জন্য এখানে তিনটি উপায় রয়েছে:

async Task<T> SomethingAsync() { ... return t; }
async Task SomethingAsync() { ... }
async void SomethingAsync() { ... }

সমস্ত ক্ষেত্রে, ফাংশনটি কাজের একটি শৃঙ্খলে রূপান্তরিত হয়। পার্থক্যটি ফাংশনটি কী দেয়।

প্রথম ক্ষেত্রে, ফাংশনটি এমন একটি কার্য দেয় যা শেষ পর্যন্ত টি তৈরি করে।

দ্বিতীয় ক্ষেত্রে, ফাংশনটি এমন কোনও টাস্ক দেয় যাটির কোনও পণ্য নেই, তবে এটি কখন শেষ হবে তা জানতে আপনি অপেক্ষা করতে পারেন।

তৃতীয় কেসটি কদর্য। তৃতীয় কেসটি দ্বিতীয় কেসের মতো, আপনি এমনকি টাস্কটি ফিরে পাবেন না except ফাংশনের কাজটি কখন শেষ হয়েছে তা জানার আপনার কোনও উপায় নেই।

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


6

আমি মনে করি আপনি async voidব্যতিক্রমগুলি ধরতে যতক্ষণ যত্নবান হন ততক্ষণ আপনি ব্যাকগ্রাউন্ড অপারেশনগুলিও লাথি মারতে ব্যবহার করতে পারেন । থটস?

class Program {

    static bool isFinished = false;

    static void Main(string[] args) {

        // Kick off the background operation and don't care about when it completes
        BackgroundWork();

        Console.WriteLine("Press enter when you're ready to stop the background operation.");
        Console.ReadLine();
        isFinished = true;
    }

    // Using async void to kickoff a background operation that nobody wants to be notified about when it completes.
    static async void BackgroundWork() {
        // It's important to catch exceptions so we don't crash the appliation.
        try {
            // This operation will end after ten interations or when the app closes. Whichever happens first.
            for (var count = 1; count <= 10 && !isFinished; count++) {
                await Task.Delay(1000);
                Console.WriteLine($"{count} seconds of work elapsed.");
            }
            Console.WriteLine("Background operation came to an end.");
        } catch (Exception x) {
            Console.WriteLine("Caught exception:");
            Console.WriteLine(x.ToString());
        }
    }
}

1
অ্যাসিঙ্ককে অকার্যকর বলার সমস্যাটি
হ'ল আপনিও

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

একটি অ্যাসিঙ্ক অকার্যকর পদ্ধতি থেকে ব্যতিক্রম ধরা যায় না। এমএসডিএন.মাইক্রোসফটকম /en-us/magazine/jj991977.aspx
সি জি

3
@ সিজি সিটিকে ক্যাচটি উদাহরণ হিসাবে দেখানো হয়েছে async শূন্য পদ্ধতিতে প্রবেশ করানো হয়েছে এবং এটি ধরা পড়ে।
bboyle1234

আপনার প্রয়োজনীয়তাগুলি কোনও কাজ না করার প্রয়োজনে পরিবর্তিত হয় যদি আপনি লগইন করতে না পারেন - তবে আপনাকে বর্তমানে সম্পূর্ণ যুক্তিটি পরিবর্তনের পরিবর্তে আপনার সম্পূর্ণ API এ স্বাক্ষর পরিবর্তন করতে হবে // ব্যতিক্রম উপেক্ষা করুন
মিলনে

0

আমার উত্তরটি সহজ আপনি শূন্য পদ্ধতিটির জন্য অপেক্ষা করতে পারবেন না

Error   CS4008  Cannot await 'void' TestAsync   e:\test\TestAsync\TestAsyncProgram.cs

সুতরাং পদ্ধতিটি যদি অ্যাসিঙ্ক হয় তবে অপেক্ষা করা ভাল, কারণ আপনি অ্যাসিঙ্ক সুবিধাটি looseিলা করতে পারেন।


-2

মাইক্রোসফ্ট ডকুমেন্টেশন অনুসারে , কখনও ব্যবহার করা উচিত নয়async void

এটি করবেন না: নিম্নলিখিত async voidপ্রত্যাশাটি ব্যবহার করে যা প্রথম প্রত্যাশায় পৌঁছালে HTTP অনুরোধটি সম্পূর্ণ করে তোলে:

  • যা এএসপি.এনইটি কোর অ্যাপ্লিকেশনগুলিতে সর্বদা একটি খারাপ অভ্যাস।

  • এইচটিটিপি অনুরোধটি সম্পূর্ণ হওয়ার পরে এইচটিপিআরস্পোনেস অ্যাক্সেস করে।

  • প্রক্রিয়া ক্রাশ।

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