একটি প্রধান পার্থক্য ব্যতিক্রম প্রচার হয়। ব্যতিক্রম, একটি ভিতরে নিহিত async Task
পদ্ধতি, ফিরে সঞ্চিত পরার Task
বস্তু এবং সুপ্ত থাকে যতক্ষণ না কাজটি মাধ্যমে পালিত পরার await task
, task.Wait()
, task.Result
বা task.GetAwaiter().GetResult()
। পদ্ধতির সিঙ্ক্রোনাস অংশ থেকে ফেলে দেওয়া হলেও এটি এইভাবে প্রচার করা হয় async
।
নিম্নলিখিত কোডটি বিবেচনা করুন, যেখানে OneTestAsync
এবং AnotherTestAsync
বেশ আলাদাভাবে আচরণ করে:
static async Task OneTestAsync(int n)
{
await Task.Delay(n);
}
static Task AnotherTestAsync(int n)
{
return Task.Delay(n);
}
static void DoTestAsync(Func<int, Task> whatTest, int n)
{
Task task = null;
try
{
task = whatTest(n);
Console.Write("Press enter to continue");
Console.ReadLine();
task.Wait();
}
catch (Exception ex)
{
Console.Write("Error: " + ex.Message);
}
}
যদি আমি কল করি DoTestAsync(OneTestAsync, -2)
তবে এটি নিম্নলিখিত আউটপুট উত্পাদন করে:
চালিয়ে যাওয়ার জন্য এন্টার টিপুন
ত্রুটি: এক বা একাধিক ত্রুটি ঘটেছে awa
ত্রুটি: 2 য়
দ্রষ্টব্য, Enterএটি দেখতে আমাকে টিপতে হয়েছিল।
এখন, যদি আমি কল করি DoTestAsync(AnotherTestAsync, -2)
, তবে কোড ওয়ার্কফ্লো ভিতরে DoTestAsync
। এবার আমাকে টিপতে বলা হয়নি Enter:
ত্রুটি: মানটি -1 হওয়া উচিত (অসীম সময়সীমা নির্দেশ করে), 0 বা ধনাত্মক পূর্ণসংখ্যা।
প্যারামিটারের নাম: মিলিসেকেন্ডসডেলিআরার: 1 ম
উভয় ক্ষেত্রে Task.Delay(-2)
এর পরামিতিগুলি যাচাই করার সময় শুরুতে ছুড়ে দেয়। এটি একটি Task.Delay(1000)
অন্তর্নিহিত দৃশ্য হতে পারে, তবে তাত্ত্বিকভাবে খুব সম্ভবত ফেলে দিতে পারে, উদাহরণস্বরূপ, যখন অন্তর্নিহিত সিস্টেমের টাইমার এপিআই ব্যর্থ হয়।
পার্শ্ব নোটে, ত্রুটি প্রচারের যুক্তি async void
পদ্ধতিগুলির জন্য এখনও পৃথক ( পদ্ধতিগুলির বিপরীতে async Task
)। কোনও async void
পদ্ধতির অভ্যন্তরে উত্থাপিত একটি ব্যতিক্রম তাত্ক্ষণিকভাবে বর্তমান থ্রেডের সিঙ্ক্রোনাইজেশন প্রসঙ্গে (মাধ্যমে SynchronizationContext.Post
) SynchronizationContext.Current != null)
পুনরায় নিক্ষেপ করা হবে , যদি বর্তমান থ্রেডটিতে একটি থাকে ( অন্যথায়, এটি পুনরায় নিক্ষেপ করা হবে ThreadPool.QueueUserWorkItem
)। কলারের কাছে একই স্ট্যাক ফ্রেমে এই ব্যতিক্রমটি পরিচালনা করার সুযোগ নেই।
আমি TPL ব্যতিক্রম হ্যান্ডলিং আচরণ সম্পর্কে আরো কিছু বিবরণ পোস্ট এখানে এবং এখানে ।
প্রশ্ন : async
অ-অ্যাসিঙ্ক Task
ভিত্তিক পদ্ধতিগুলির জন্য ব্যতিক্রমী প্রচারের পদ্ধতিগুলি কী নকল করা সম্ভব , যাতে পরবর্তীকর্তারা একই স্ট্যাক ফ্রেমের উপর না ফেলে?
উত্তর : যদি সত্যিই প্রয়োজন হয়, তবে হ্যাঁ, এর জন্য একটি কৌশল আছে:
async Task<int> MethodAsync(int arg)
{
if (arg < 0)
throw new ArgumentException("arg");
return 42 + arg;
}
Task<int> MethodAsync(int arg)
{
var task = new Task<int>(() =>
{
if (arg < 0)
throw new ArgumentException("arg");
return 42 + arg;
});
task.RunSynchronously(TaskScheduler.Default);
return task;
}
তবে নোট করুন, কিছু শর্তের মধ্যে (যেমন এটি স্ট্যাকের খুব গভীর তখন) RunSynchronously
তবুও তাত্পর্যপূর্ণভাবে কার্যকর করতে পারে।
আরেকটি উল্লেখযোগ্য পার্থক্য যে
/ সংস্করণ আরো মৃত লক একটি অ-ডিফল্ট সিঙ্ক্রোনাইজেশন প্রসঙ্গের উপর প্রবণ । উদাহরণস্বরূপ, নিম্নলিখিতগুলিতে একটি উইনফোর্ডস বা ডাব্লুপিএফ অ্যাপ্লিকেশনটিতে মৃত-লক হবে:
async
await
static async Task TestAsync()
{
await Task.Delay(1000);
}
void Form_Load(object sender, EventArgs e)
{
TestAsync().Wait();
}
এটিকে একটি অ্যাসিঙ্ক সংস্করণে পরিবর্তন করুন এবং এটি মৃত-লক হবে না:
Task TestAsync()
{
return Task.Delay(1000);
}
মৃত-লকটির প্রকৃতিটি তার ব্লগে স্টিফেন ক্লিয়ারি দ্বারা ভালভাবে ব্যাখ্যা করা হয়েছে ।
await
/ ব্যবহার করার কোনও মানেasync
হবে না :)