Task.WhenAll
.NET কোর 3.0 এ চলার সময়, পদ্ধতি সম্পর্কে আমি কেবল একটি কৌতূহলী পর্যবেক্ষণ করেছি । আমি Task.Delay
একক যুক্তি হিসাবে একটি সাধারণ কাজটি Task.WhenAll
পেরিয়েছি এবং আমি প্রত্যাশা করেছি যে মোড়ানো টাস্কটি মূল টাস্কের সাথে একই রকম আচরণ করবে। তবে এই ঘটনাটি নয়। মূল টাস্কের ধারাবাহিকতাগুলি অবিচ্ছিন্নভাবে কার্যকর করা হয় (যা পছন্দসই) এবং একাধিক Task.WhenAll(task)
মোড়কের ধারাবাহিকতা একের পর এক সিঙ্ক্রোনিকভাবে কার্যকর করা হয় (যা অনাকাঙ্ক্ষিত)।
এই আচরণের একটি ডেমো এখানে । চারটি কর্মী Task.Delay
সমাপ্তির জন্য একই কাজটির জন্য অপেক্ষা করছে এবং তারপরে ভারী গণনা (একটি দ্বারা সিমুলেটেড Thread.Sleep
) দিয়ে চালিয়ে যান ।
var task = Task.Delay(500);
var workers = Enumerable.Range(1, 4).Select(async x =>
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} before await");
await task;
//await Task.WhenAll(task);
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} after await");
Thread.Sleep(1000); // Simulate some heavy CPU-bound computation
}).ToArray();
Task.WaitAll(workers);
এখানে আউটপুট। চারটি ধারাবাহিকতা বিভিন্ন থ্রেডে (সমান্তরালে) প্রত্যাশার মতো চলছে।
05:23:25.511 [1] Worker1 before await
05:23:25.542 [1] Worker2 before await
05:23:25.543 [1] Worker3 before await
05:23:25.543 [1] Worker4 before await
05:23:25.610 [4] Worker1 after await
05:23:25.610 [7] Worker2 after await
05:23:25.610 [6] Worker3 after await
05:23:25.610 [5] Worker4 after await
এখন আমি যদি লাইনটি মন্তব্য করি await task
এবং নীচের লাইনে await Task.WhenAll(task)
কোনও অসুবিধা না করি তবে আউটপুটটি বেশ আলাদা। সমস্ত ধারাবাহিকতা একই থ্রেডে চলছে, সুতরাং গণনা সমান্তরাল হয় না। প্রতিটি গণনা পূর্ববর্তীটি শেষ হওয়ার পরে শুরু হচ্ছে:
05:23:46.550 [1] Worker1 before await
05:23:46.575 [1] Worker2 before await
05:23:46.576 [1] Worker3 before await
05:23:46.576 [1] Worker4 before await
05:23:46.645 [4] Worker1 after await
05:23:47.648 [4] Worker2 after await
05:23:48.650 [4] Worker3 after await
05:23:49.651 [4] Worker4 after await
আশ্চর্যজনকভাবে এটি তখনই ঘটে যখন প্রতিটি শ্রমিক আলাদা আলাদা মোড়কের জন্য অপেক্ষা করে। যদি আমি মোড়কটিকে সামনে থেকে সংজ্ঞায়িত করি:
var task = Task.WhenAll(Task.Delay(500));
... এবং তারপরে await
সমস্ত কর্মীদের মধ্যে একই কাজ, আচরণটি প্রথম ক্ষেত্রে (অ্যাসিনক্রোনাস ধারাবাহিকতা) এর মতো।
আমার প্রশ্ন: কেন এমন হচ্ছে? একই কাজটির একই সাথে বিভিন্ন মোড়কের ক্রিয়াকলাপকে একই সুতায় চালিত করার কারণ কী?
দ্রষ্টব্য: একই অদ্ভুত আচরণের ফলাফলের Task.WhenAny
পরিবর্তে কোনও কার্য মোড়ানো Task.WhenAll
।
অন্য একটি পর্যবেক্ষণ: আমি প্রত্যাশা করেছি যে একটি এর ভিতরে মোড়ক মুড়িয়ে দেওয়া Task.Run
ধারাবাহিকতাগুলিকে অবিচ্ছিন্ন করে তুলবে। তবে তা হচ্ছে না। নীচের লাইনের ধারাবাহিকতাগুলি এখনও একই থ্রেডে (সমকালীনভাবে) কার্যকর করা হয়।
await Task.Run(async () => await Task.WhenAll(task));
স্পষ্টকরণ: উপরের পার্থক্যগুলি .NET কোর 3.0 প্ল্যাটফর্মে চলমান একটি কনসোল অ্যাপ্লিকেশনটিতে লক্ষ্য করা গেছে। .NET ফ্রেমওয়ার্ক 4.8 এ, মূল টাস্ক বা টাস্ক-র্যাপারের অপেক্ষার মধ্যে কোনও পার্থক্য নেই। উভয় ক্ষেত্রে, ধারাবাহিকতা একই থ্রেডে, সুসংগতভাবে কার্যকর করা হয়।
Task.WhenAll
Task.Delay
থেকে 100
থেকে 1000
এটা সম্পূর্ণ না যাতে যখন await
ইডি।
await Task.WhenAll(new[] { task });
?