আমি কখন টাস্ক.ইয়েলড () ব্যবহার করব?


218

আমি অ্যাসিঙ্ক / অপেক্ষারত এবং Taskঅনেকগুলি ব্যবহার করছি তবে কখনই ব্যবহার করা হয়নি Task.Yield()এবং এমন সমস্ত ব্যাখ্যা দিয়েও সৎ হতে আমি কেন বুঝতে পারি না কেন আমাকে এই পদ্ধতির প্রয়োজন হবে।

কেউ Yield()প্রয়োজন যেখানে প্রয়োজন একটি ভাল উদাহরণ দিতে পারেন ?

উত্তর:


241

আপনি যখন async/ ব্যবহার করেন তখন awaitকোনও গ্যারান্টি নেই যে আপনি যখন কল করবেন তখন যে পদ্ধতিটি করা await FooAsync()হবে তা আসলে অ্যাসিনক্রোনালি চালিত হবে। অভ্যন্তরীণ বাস্তবায়ন সম্পূর্ণ সিঙ্ক্রোনাস পথ ব্যবহার করে ফিরতে মুক্ত।

আপনি যদি এমন কোনও এপিআই তৈরি করেন যেখানে এটি গুরুতর যে আপনি অবরুদ্ধ করবেন না এবং আপনি কিছু কোডকে অবিচ্ছিন্নভাবে চালনা করছেন, এবং এমন একটি সম্ভাবনা রয়েছে যে কল করা পদ্ধতিটি সিঙ্ক্রোনিকভাবে চলবে (কার্যকরভাবে অবরুদ্ধ করা), await Task.Yield()আপনার পদ্ধতিটি অ্যাসিক্রোনাস হতে বাধ্য করবে এবং ফিরে আসবে এই সময়ে নিয়ন্ত্রণ কোডের বাকী অংশটি পরবর্তী সময়ে কার্যকর করা হবে (যে সময়ে এটি এখনও সুসংগতভাবে চলতে পারে) বর্তমান প্রসঙ্গে।

আপনি যদি একটি অ্যাসিনক্রোনাস পদ্ধতি তৈরি করেন যা কিছু "দীর্ঘ চলমান" সূচনা প্রয়োজন, যেমন:

 private async void button_Click(object sender, EventArgs e)
 {
      await Task.Yield(); // Make us async right away

      var data = ExecuteFooOnUIThread(); // This will run on the UI thread at some point later

      await UseDataAsync(data);
 }

Task.Yield()কল ছাড়াই , পদ্ধতিটি প্রথম কলটিতে সমস্তভাবে সিঙ্ক্রোনসিভভাবে কার্যকর করবে await


26
আমার মনে হচ্ছে আমি এখানে কিছু ভুল ব্যাখ্যা করছি। যদি await Task.Yield()পদ্ধতিটিকে অ্যাসিঙ্ক হতে বাধ্য করে, তবে আমরা কেন "আসল" অ্যাসিঙ্ক কোডটি লিখতে বিরক্ত করব? একটি ভারী সিঙ্ক পদ্ধতি কল্পনা করুন। এ্যাসিঙ্ক তৈরি করতে, কেবল যুক্ত করুন asyncএবং await Task.Yield()শুরুতে এবং যাদুকরীভাবে, এটি অ্যাসিঙ্ক হবে? এটি বেশিরভাগ ক্ষেত্রে সমস্ত সিঙ্ক কোডটি মোড়ানো Task.Run()এবং একটি জাল অ্যাসিঙ্ক পদ্ধতি তৈরির মতো হবে ।
ক্রুমেলুর

14
@ ক্রুমেলুর একটি বড় পার্থক্য রয়েছে - আমার উদাহরণটি দেখুন। আপনি যদি Task.Runএটি প্রয়োগ করতে একটি ব্যবহার ExecuteFooOnUIThreadকরেন তবে থাই পুলটিতে চলবে, ইউআই থ্রেড নয়। এর সাথে await Task.Yield(), আপনি এটিকে এমনভাবে অবিচ্ছিন্ন হতে বাধ্য করেন যে পরবর্তী কোডটি এখনও বর্তমান প্রসঙ্গে (সময়ের পরে ঠিক সময়ে) চালিত হয়। এটি আপনি সাধারণত করেন এমন কিছু নয়, তবে এটি দুর্দান্ত যে কোনও অদ্ভুত কারণে যদি এটির প্রয়োজন হয় তবে বিকল্প রয়েছে।
রিড কোপসি

7
আরও একটি প্রশ্ন: যদি ExecuteFooOnUIThread()খুব দীর্ঘ সময় চলতে থাকে তবে এটি এখনও কোনও সময়ে ইউআই থ্রেডকে দীর্ঘ সময়ের জন্য অবরুদ্ধ করে এবং ইউআইকে প্রতিক্রিয়াহীন করে তুলবে, এটি কি সঠিক?
ক্রুমেলুর

7
@ ক্রুমেলুর হ্যাঁ, এটি হবে। কেবল তাত্ক্ষণিকভাবে নয় - এটি পরবর্তী সময়ে ঘটবে।
রিড কোপসি

33
যদিও এই উত্তরটি প্রযুক্তিগতভাবে সঠিক, "বাকী কোডটি পরবর্তী সময়ে কার্যকর হবে" বিবৃতিটি খুব বিমূর্ত এবং বিভ্রান্তিকর হতে পারে। কার্যের পরে কোডটির কার্যকরকরণের শিডিয়ুল ieldয়েল্ড () কংক্রিট সিঙ্ক্রোনাইজেশন কনটেক্সট এর উপর অনেক বেশি নির্ভরশীল। এবং এমএসডিএন ডকুমেন্টেশন পরিষ্কারভাবে বলেছে যে "বেশিরভাগ ইউআই পরিবেশে ইউআই থ্রেডে উপস্থিত সিঙ্ক্রোনাইজেশন প্রসঙ্গটি প্রায়শই ইনপুট এবং রেন্ডারিংয়ের কাজের চেয়ে বেশি প্রসঙ্গে পোস্ট করা কাজের অগ্রাধিকার দেয় this এই কারণে, টাস্কের অপেক্ষায় নির্ভর করবেন না Y ফলস () একটি ইউআই প্রতিক্রিয়াশীল রাখতে। "
ভাইটালিয়্য সোয়েয়ার

36

অভ্যন্তরীণভাবে, await Task.Yield()কেবল পারেন বর্তমান সিঙ্ক্রোনাইজেশন প্রসঙ্গ বা একটি র্যান্ডম পুকুর থ্রেডে ধারাবাহিকতা queues, যদি SynchronizationContext.Currentহয় null

এটি কাস্টম ওয়েটার হিসাবে দক্ষতার সাথে প্রয়োগ করা হয়েছে। অভিন্ন প্রভাব উত্পাদন একটি কম দক্ষ কোড এই হিসাবে সহজ হতে পারে:

var tcs = new TaskCompletionSource<bool>();
var sc = SynchronizationContext.Current;
if (sc != null)
    sc.Post(_ => tcs.SetResult(true), null);
else
    ThreadPool.QueueUserWorkItem(_ => tcs.SetResult(true));
await tcs.Task;

Task.Yield()কিছু অদ্ভুত এক্সিকিউশন প্রবাহ পরিবর্তনের জন্য একটি শর্ট-কাট হিসাবে ব্যবহার করা যেতে পারে। উদাহরণ স্বরূপ:

async Task DoDialogAsync()
{
    var dialog = new Form();

    Func<Task> showAsync = async () => 
    {
        await Task.Yield();
        dialog.ShowDialog();
    }

    var dialogTask = showAsync();
    await Task.Yield();

    // now we're on the dialog's nested message loop started by dialog.ShowDialog 
    MessageBox.Show("The dialog is visible, click OK to close");
    dialog.Close();

    await dialogTask;
    // we're back to the main message loop  
}

এটি বলেছিল, আমি এমন কোনও ক্ষেত্রে ভাবতে পারি না যেখানে ডাব্লু / যথাযথ টাস্ক শিডিয়ুলারের Task.Yield()সাথে প্রতিস্থাপন করা যায় না Task.Factory.StartNew

আরো দেখুন:


আপনার উদাহরণস্বরূপ, সেখানে এবং এর মধ্যে পার্থক্য কী var dialogTask = await showAsync();?
এরিক ফিলিপস

@ এরিক ফিলিপস, var dialogTask = await showAsync()সংকলন করবে না কারণ await showAsync()এক্সপ্রেশনটি কোনও ফিরে আসে না Task(এটি ব্যতীত ভিন্ন await)। এটি বলে, যদি আপনি await showAsync()এটি করেন তবে ডায়ালগটি বন্ধ হয়ে যাওয়ার পরে তার কার্যকর করা পুনরায় শুরু করা হবে, এটাই আলাদা। কারণ window.ShowDialogএটি একটি সিঙ্ক্রোনাস এপিআই (এটি বার্তা পাম্প সত্ত্বেও)। সেই কোডটিতে, আমি ডায়ালগটি এখনও প্রদর্শিত থাকার সময় চালিয়ে যেতে চেয়েছিলাম।
নাসেরটিও

5

এর একটি ব্যবহার Task.Yield()হ'ল অ্যাসিঙ্ক পুনরাবৃত্তি করার সময় স্ট্যাকের ওভারফ্লো প্রতিরোধ করা। Task.Yield()সিঙ্ক্রোনাস ধারাবাহিকতা রোধ করে। তবে নোট করুন, এর ফলে এটি আউটআফমিউরি ব্যতিক্রম ঘটতে পারে (যেমন ট্রায়ঙ্কো উল্লেখ করেছেন)। অন্তহীন পুনরাবৃত্তি এখনও নিরাপদ নয় এবং আপনি সম্ভবত লুপ হিসাবে পুনরাবৃত্তি পুনর্লিখন আরও ভাল।

private static void Main()
    {
        RecursiveMethod().Wait();
    }

    private static async Task RecursiveMethod()
    {
        await Task.Delay(1);
        //await Task.Yield(); // Uncomment this line to prevent stackoverlfow.
        await RecursiveMethod();
    }

4
এটি স্ট্যাকের ওভারফ্লো প্রতিরোধ করতে পারে, তবে আপনি যদি এটি দীর্ঘকাল চালাতে দেন তবে এটি শেষ পর্যন্ত সিস্টেমের মেমরির বাইরে চলে যাবে। প্রতিটি পুনরাবৃত্তি একটি নতুন টাস্ক তৈরি করবে যা কখনই সম্পূর্ণ হয় না, কারণ বাহ্যিক কার্য কোনও অভ্যন্তরীণ টাস্কের অপেক্ষায় রয়েছে, যা আরও একটি অভ্যন্তরীণ টাস্কের জন্য অপেক্ষা করছে, এবং আরও so এটি ঠিক নেই। বিকল্পভাবে, আপনার কেবল একটি বহিরাগত টাস্ক থাকতে পারে যা কখনই সম্পূর্ণ হয় না এবং পুনরাবৃত্তির পরিবর্তে এটি লুপ করে। টাস্কটি কখনই সম্পূর্ণ হয় না, তবে কেবলমাত্র তাদের মধ্যে একটি থাকবে। লুপের অভ্যন্তরে এটি আপনার পছন্দসই কিছু পেতে বা অপেক্ষা করতে পারে।
ট্রায়ঙ্কো

আমি স্ট্যাকের ওভারফ্লো পুনরুত্পাদন করতে পারি না। দেখে মনে হচ্ছে এটি await Task.Delay(1)প্রতিরোধের জন্য যথেষ্ট। (কনসোল অ্যাপ
,।

-8

Task.Yield() অ্যাসিঙ্ক পদ্ধতির মক বাস্তবায়নে ব্যবহৃত হতে পারে।


4
আপনার কিছু বিশদ সরবরাহ করা উচিত।
পিজেপ্রুডন

3
এই উদ্দেশ্যে, আমি বরং Task.CompletedTask ব্যবহার করব - আরও বিবেচনার জন্য এই এমএসডিএন ব্লগ পোস্টে Task.CompletedTask বিভাগটি দেখুন।
গ্রেজগোর্জ স্মুলকো

2
Task.CompletedTask, বা Task.FromResult ব্যবহার করে সমস্যাটি হ'ল আপনি যখন ত্রুটিগুলি কেবল মিস করতে পারেন তখনই পদ্ধতিটি অ্যাসিঙ্ক্রোনাস কার্যকর করে।
জোয়াকিম এমএইচ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.