এ্যাসিঙ্ক তৈরি করার জন্য আপনাকে কি কোনও পদ্ধতিতে টাস্ক.আর চালাতে হবে?


304

আমি সহজ ফর্মটি হিসাবে অ্যাসিঙ্কের অপেক্ষা করার বিষয়টি বোঝার চেষ্টা করছি। আমি একটি খুব সহজ পদ্ধতি তৈরি করতে চাই যা এই উদাহরণের জন্য দুটি সংখ্যা যুক্ত করে দেয়, মঞ্জুর হয়, এটি কোনও প্রসেসিংয়ের সময় নয়, এটি এখানে একটি উদাহরণ তৈরির বিষয় মাত্র।

উদাহরণ 1

private async Task DoWork1Async()
{
    int result = 1 + 2;
}

উদাহরণ 2

private async Task DoWork2Async()
{
    Task.Run( () =>
    {
        int result = 1 + 2;
    });
}

আমি যদি অপেক্ষা করি DoWork1Async()তবে কোডটি কি সিঙ্ক্রোনসিভ বা অ্যাসিনক্রোনালি চালিত হবে?

Task.Runইউআই থ্রেডটি ব্লক না করার জন্য পদ্ধতিটিকে প্রতীক্ষিত ও অ্যাসিঙ্ক্রোনাস তৈরি করতে আমার কি সিঙ্ক কোডটি মোড়ানো দরকার ?

আমি জিনিসটা যদি আমার পদ্ধতি একটি হল চেষ্টা করছি Taskবা আয় Task<T>আমি কোড মোড়ানো করতে হবে Task.Runএটা অ্যাসিঙ্ক্রোনাস করা।

মূঢ় প্রশ্ন আমি নিশ্চিত কিন্তু আমি নেট যেখানে লোকেরা কোডের ভিতর কিছুই ASYNC এবং একটি আবৃত না যে অপেক্ষা করছে উপর উদাহরণগুলি দেখুন Task.Runবা StartNew


30
আপনার প্রথম স্নিপেট কি কোনও সতর্কতা দিচ্ছে না?
সোভিক

উত্তর:


586

প্রথমে কিছু পরিভাষা পরিষ্কার করা যাক: "অ্যাসিনক্রোনাস" ( async) এর অর্থ এটি কলিং থ্রেড শুরু হওয়ার আগেই ফিরে আসতে পারে yield একটি asyncপদ্ধতিতে, সেই "ফলন" পয়েন্টগুলি awaitহ'ল প্রকাশ।

এটি "অ্যাসিঙ্ক্রোনাস" শব্দটির থেকে খুব আলাদা, কারণ এমএসডিএন ডকুমেন্টেশন দ্বারা "ব্যাকগ্রাউন্ড থ্রেডে এক্সিকিউটস" বোঝাতে বছরের পর বছর ধরে ব্যবহৃত হয়েছে (ভুল) mis

ইস্যুটিকে আরও বিভ্রান্ত করার asyncজন্য "প্রতীক্ষিত" এর চেয়ে আলাদা; কিছু asyncপদ্ধতি রয়েছে যার প্রত্যাবর্তনের ধরণগুলি প্রত্যাশিত নয় এবং অনেক পদ্ধতি প্রত্যাশিত ধরণের প্রত্যাবর্তনকারী নয় async

যা তারা নয় তা যথেষ্ট ; এখানে তারা কি হয় :

  • asyncশব্দ একটি অ্যাসিঙ্ক্রোনাস পদ্ধতি পারবেন (যে, এটা করতে পারবেন awaitএক্সপ্রেশন)। asyncপদ্ধতি ফেরত দিতে পারেন Task, Task<T>অথবা (যদি আপনি আবশ্যক) void
  • কোনও নির্দিষ্ট ধরণ অনুসরণ করে এমন কোনও ধরণের অপেক্ষারত হতে পারে। সবচেয়ে সাধারণ awaitable ধরনের হয় Taskএবং Task<T>

সুতরাং, আমরা যদি আপনার প্রশ্নের "কীভাবে ব্যাকগ্রাউন্ড থ্রেডের জন্য অপেক্ষাকৃতভাবে অপারেশন চালাতে পারি" তে এটি সংশোধন করি তবে উত্তরটি ব্যবহার করতে হবে Task.Run:

private Task<int> DoWorkAsync() // No async because the method does not need await
{
  return Task.Run(() =>
  {
    return 1 + 2;
  });
}

(তবে এই নিদর্শনটি একটি দুর্বল পদ্ধতির; নীচে দেখুন)।

তবে যদি আপনার প্রশ্নটি হয় "আমি কীভাবে এমন একটি asyncপদ্ধতি তৈরি করব যা ব্লকিংয়ের পরিবর্তে তার কলারের কাছে ফিরে আসতে পারে", উত্তরটি হল পদ্ধতিটি ঘোষণা করা asyncএবং awaitতার "ফলনশীল" পয়েন্টগুলির জন্য ব্যবহার করা:

private async Task<int> GetWebPageHtmlSizeAsync()
{
  var client = new HttpClient();
  var html = await client.GetAsync("http://www.example.com/");
  return html.Length;
}

সুতরাং, জিনিসগুলির প্রাথমিক প্যাটার্ন হ'ল asyncকোডটি তার awaitএক্সপ্রেশনগুলিতে "প্রতীক্ষিত "গুলির উপর নির্ভর করে । এই "প্রতীক্ষিত "গুলি অন্যান্য asyncপদ্ধতি বা কেবল নিয়মিত পদ্ধতিগুলির জন্য প্রত্যাবর্তনযোগ্য হতে পারে। ফিরে নিয়মিত পদ্ধতি Task/ Task<T> করতে ব্যবহার Task.Runএকটি ব্যাকগ্রাউন্ড থ্রেডে কোড এক্সিকিউট করা অথবা (আরো সাধারণভাবে) তারা ব্যবহার করতে পারেন TaskCompletionSource<T>বা তার শর্টকাট (এক TaskFactory.FromAsync, Task.FromResultইত্যাদি)। আমি না একটি সমগ্র পদ্ধতি মোড়কে সুপারিশ Task.Run; সিঙ্ক্রোনাস পদ্ধতিতে সিঙ্ক্রোনাস স্বাক্ষর থাকতে হবে এবং এটি একটিতে আবৃত করা উচিত কিনা তা গ্রাহকের উপর ছেড়ে দেওয়া উচিত Task.Run:

private int DoWork()
{
  return 1 + 2;
}

private void MoreSynchronousProcessing()
{
  // Execute it directly (synchronously), since we are also a synchronous method.
  var result = DoWork();
  ...
}

private async Task DoVariousThingsFromTheUIThreadAsync()
{
  // I have a bunch of async work to do, and I am executed on the UI thread.
  var result = await Task.Run(() => DoWork());
  ...
}

আমি একজন আছে async/ awaitইন্ট্রো আমার ব্লগে; শেষে কিছু ভাল ফলোআপ সংস্থান আছে। এর জন্য এমএসডিএন ডক্সও asyncঅস্বাভাবিকভাবে ভাল।


8
@ স্পেনস্যাজগন: হ্যাঁ asyncপদ্ধতি ফিরে আসবে Task, Task<T>অথবা voidTaskএবং Task<T>প্রতীক্ষিত; voidএটি না.
স্টিফেন ক্লিয়ারি

3
আসলে, একটি async voidপদ্ধতির স্বাক্ষরটি সংকলন করবে, এটি আপনার
অ্যাসিঙ্ক

4
@ টপিনফ্রেসি: হ্যাঁ, তারা সংকলন করবে, তবে voidএটি অপেক্ষায় নেই।
স্টিফেন ক্লিয়ারি

4
@ ওহাদিনহো: না, ব্লগ পোস্টে আমি যে বিষয়ে কথা বলছি তা হ'ল যখন সম্পূর্ণ পদ্ধতিটি কেবলমাত্র Task.Run( DoWorkAsyncএই উত্তরের মত ) কল করতে পারে । কোনও ইউআই প্রসঙ্গ থেকে কোনও পদ্ধতিতে কলTask.Run করতে ব্যবহার করা উপযুক্ত (যেমন )। DoVariousThingsFromTheUIThreadAsync
স্টিফেন ক্লিয়ারি

2
হ্যাঁ অবশ্যই. কোনও পদ্ধতিটি আহ্বানTask.Run করার জন্য এটি ব্যবহারযোগ্য বৈধ , তবে যদি পদ্ধতির কোডটিরTask.Run প্রায় সমস্ত (বা প্রায় সমস্ত) থাকে তবে এটি একটি বিরোধী-প্যাটার্ন - কেবল সেই পদ্ধতিটিকে সিঙ্ক্রোনাস রাখুন এবং Task.Runএকটি স্তরকে উপরে নিয়ে যান।
স্টিফেন ক্লিয়ারি

22

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

private Task<int> DoWorkAsync()
{
    //create a task completion source
    //the type of the result value must be the same
    //as the type in the returning Task
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    Task.Run(() =>
    {
        int result = 1 + 2;
        //set the result to TaskCompletionSource
        tcs.SetResult(result);
    });
    //return the Task
    return tcs.Task;
}

private async void DoWork()
{
    int result = await DoWorkAsync();
}

26
টাস্ক.রুন () পদ্ধতিতে (এবং ফলাফলটি ফিরে আসার জন্য এটির দেহ পরিবর্তন করা) পরিবর্তে আপনি কেবল টাস্ক কমপ্লিটসোর্স ব্যবহার করবেন না কেন?
অদ্ভুত

4
শুধু একটি পার্শ্ব নোট। একটি "অ্যাসিঙ্ক অকার্যকর" স্বাক্ষরযুক্ত একটি পদ্ধতি সাধারণত খারাপ অনুশীলন এবং খারাপ কোড হিসাবে বিবেচিত হয় কারণ এটি ইউআই অচল হয়ে যেতে পারে খুব সহজেই। মূল ব্যতিক্রম হ'ল অ্যাসিনক্রোনাস ইভেন্ট হ্যান্ডলার।
জাজেরোকি

12

আপনি যখন কোনও পদ্ধতি চালানোর জন্য টাস্ক.আর ব্যবহার করেন, সেই পদ্ধতিটি চালানোর জন্য টাস্ক থ্রেডপুল থেকে একটি থ্রেড পায়। সুতরাং ইউআই থ্রেডের দৃষ্টিকোণ থেকে এটি "অ্যাসিনক্রোনাস" কারণ এটি ইউআই থ্রেডকে ব্লক করে না desktop ডেস্কটপ অ্যাপ্লিকেশনটির জন্য এটি ঠিক আছে কারণ ব্যবহারকারীর ইন্টারঅ্যাকশন যত্ন নেওয়ার জন্য সাধারণত আপনার অনেক থ্রেডের প্রয়োজন হয় না।

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

সত্যিকারের Async অগত্যা I / O অপারেশনগুলির জন্য কোনও থ্রেড, যেমন ফাইল / ডিবি অ্যাক্সেস ইত্যাদির জন্য জড়িত না I I / O অপারেশন কেন থ্রেডের প্রয়োজন হয় না তা বুঝতে আপনি এটি পড়তে পারেন। http://blog.stephencleary.com/2013/11/there-is-no-thread.html

আপনার সাধারণ উদাহরণে এটি খাঁটি সিপিইউ-বাউন্ড গণনা, সুতরাং টাস্ক.রুন ব্যবহার করা ভাল।


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

আমি সম্মতি জানাই I আমি বলছি না যে আপনি টাস্ক.রুন () এর মধ্যে সমস্ত সিঙ্ক্রোনাস কলগুলি একেবারে মোড়ানো উচিত নয়। আমি কেবল সম্ভাব্য সমস্যাটি দেখিয়ে দিচ্ছি।
zheng yu

1
@ stt106 I should NOT wrap the synchronous call in Task.Run()এটি সঠিক। যদি আপনি এটি করেন তবে আপনি থ্রেডগুলি স্যুইচ করছেন। যেমন আপনি প্রাথমিক অনুরোধের থ্রেডটি অবরোধ মুক্ত করছেন তবে আপনি থ্রেডপুল থেকে অন্য একটি থ্রেড নিচ্ছেন যা অন্য অনুরোধটি প্রক্রিয়া করতে ব্যবহৃত হতে পারে। একমাত্র ফলাফলটি কনটেক্সট সুইচ ওভারহেড যখন কলটি সম্পূর্ণ শূন্য লাভের জন্য শেষ হয়
সায়েব আমিনী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.