আপনি কীভাবে সি # তে অ্যাসিক্রোনাস পদ্ধতি তৈরি করবেন?


196

আমি যে প্রতিটি ব্লগ পোস্ট পড়েছি তা সি # তে কীভাবে একটি অ্যাসিনক্রোনাস পদ্ধতি গ্রাস করতে হবে তা আপনাকে বলেছে, তবে কিছু অদ্ভুত কারণে কখন কীভাবে আপনার নিজস্ব অ্যাসিনক্রোনাস পদ্ধতি গ্রহণ করতে হয় তা ব্যাখ্যা করবেন না। সুতরাং এখনই আমার কাছে এই কোডটি রয়েছে যা আমার পদ্ধতিটি গ্রাস করে:

private async void button1_Click(object sender, EventArgs e)
{
    var now = await CountToAsync(1000);
    label1.Text = now.ToString();
}

এবং আমি এই পদ্ধতিটি লিখেছি যে CountToAsync:

private Task<DateTime> CountToAsync(int num = 1000)
{
    return Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < num; i++)
        {
            Console.WriteLine("#{0}", i);
        }
    }).ContinueWith(x => DateTime.Now);
}

এটি কি, Task.Factoryঅ্যাসিক্রোনাস পদ্ধতিটি লেখার সবচেয়ে ভাল উপায়, না আমার অন্যভাবে এটি লেখা উচিত?


22
আমি একটি পদ্ধতি কীভাবে গঠন করবেন সে সম্পর্কে একটি সাধারণ প্রশ্ন জিজ্ঞাসা করছি। আমি ইতিমধ্যে জানতে চাই যে আমার ইতিমধ্যে সিঙ্ক্রোনাস পদ্ধতিগুলি অ্যাসিক্রোনাসগুলিতে রূপান্তরিত করতে শুরু করতে হবে।
খালিদ আবুহাকমেহে

2
ঠিক আছে, তাই কি একটি টিপিক্যাল সমলয় পদ্ধতি নেই না , এবং কেন আপনি তা অ্যাসিঙ্ক্রোনাস করতে চাও ?
এরিক লিপার্ট

ধরা যাক আমাকে ব্যাচ প্রক্রিয়া করতে হবে অনেকগুলি ফাইল এবং ফলাফল অবজেক্টটি ফিরিয়ে দিতে।
খালিদ আবুহাকমেহে

1
ঠিক আছে, তাই: (1) হাই-লেটেন্সি অপারেশনটি কী: ফাইলগুলি প্রাপ্ত করা - কারণ নেটওয়ার্কটি ধীর হতে পারে, বা যা কিছু - বা প্রক্রিয়াকরণ করা - কারণ এটি সিপিইউ নিবিড়, বলুন। এবং (২) আপনি এখনও কেন বলেননি যে আপনি কেন এটি প্রথম স্থানে অবিচ্ছিন্ন হতে চান। এমন কোনও ইউআই থ্রেড রয়েছে যা আপনি অবরুদ্ধ করতে চান না বা কী?
এরিক লিপার্ট

21
@ এরিকলিপার্ট অপ্টের দেওয়া উদাহরণটি খুব মৌলিক, এটিকে এত জটিল হওয়ার দরকার নেই।
ডেভিড বি

উত্তর:


226

আপনার StartNewযদি সেই স্তরের জটিলতার প্রয়োজন না হয় আমি প্রস্তাব দিই না ।

যদি আপনার অ্যাসিঙ্ক পদ্ধতিটি অন্যান্য অ্যাসিঙ্ক পদ্ধতির উপর নির্ভরশীল হয় তবে asyncকীওয়ার্ডটি ব্যবহার করা সবচেয়ে সহজ পদ্ধতির :

private static async Task<DateTime> CountToAsync(int num = 10)
{
  for (int i = 0; i < num; i++)
  {
    await Task.Delay(TimeSpan.FromSeconds(1));
  }

  return DateTime.Now;
}

যদি আপনার অ্যাসিঙ্ক পদ্ধতিটি সিপিইউ কাজ করে তবে আপনার ব্যবহার করা উচিত Task.Run:

private static async Task<DateTime> CountToAsync(int num = 10)
{
  await Task.Run(() => ...);
  return DateTime.Now;
}

আপনি আমার async/ awaitভূমিকা উপকারী হতে পারে ।


10
@ স্টিফেন: "যদি আপনার অ্যাসিঙ্ক পদ্ধতিটি নির্ভরশীল হয় তবে অন্যান্য অ্যাসিঙ্ক পদ্ধতিগুলি" - ঠিক আছে, তবে যদি তা না হয় তবে। যদি এমন কিছু কোড মোড়ানোর চেষ্টা করছিল যা কিছু কলব্যাক কোড দিয়ে বিগিনিভোকে ফোন দেয়?
রিচিবব

1
@ রিসিবোব: আপনার মোড়ক ব্যবহার TaskFactory.FromAsyncকরা উচিত BeginInvoke। "কলব্যাক কোড" সম্পর্কে আপনি কী বোঝেন তা নিশ্চিত নন; কোড সহ আপনার নিজের প্রশ্ন পোস্ট করতে নির্দ্বিধায়।
স্টিফেন ক্লিয়ারি

@ স্টিফেন: ধন্যবাদ - হ্যাঁ টাস্কফ্যাক্টরি romফর্মএেন্সিক যা আমি খুঁজছিলাম।
রিচিবব

1
স্টিফেন, লুপের জন্য, পরবর্তী পুনরাবৃত্তি অবিলম্বে বলা হয় বা Task.Delayরিটার্নের পরে ?
jp2code

3
@ jp2code: awaitএটি একটি " অ্যাসিনক্রোনাস ওয়েট ", সুতরাং টাস্কটি শেষ না হওয়া পর্যন্ত এটি পরবর্তী পুনরাবৃত্তিতে অগ্রসর হয় না Task.Delay
স্টিফেন ক্লিয়ারি

11

আপনি যদি আপনার পদ্ধতির ভিতরে অ্যাসিঙ্কটি ব্যবহার / প্রতীক্ষা করতে না চান তবে এখনও বাইরে থেকে অপেক্ষার কীওয়ার্ডটি ব্যবহার করতে সক্ষম হবেন, এটিকে "সাজাইয়া", TaskCompletionSource.cs :

public static Task<T> RunAsync<T>(Func<T> function)
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ =>          
    { 
        try 
        {  
           T result = function(); 
           tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
   }); 
   return tcs.Task; 
}

এখান থেকে এবং এখানে

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

আমি দেখেছি। নেট উত্স যেমন। WebClient.cs :

    [HostProtection(ExternalThreading = true)]
    [ComVisible(false)]
    public Task<string> UploadStringTaskAsync(Uri address, string method, string data)
    {
        // Create the task to be returned
        var tcs = new TaskCompletionSource<string>(address);

        // Setup the callback event handler
        UploadStringCompletedEventHandler handler = null;
        handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadStringCompleted -= completion);
        this.UploadStringCompleted += handler;

        // Start the async operation.
        try { this.UploadStringAsync(address, method, data, tcs); }
        catch
        {
            this.UploadStringCompleted -= handler;
            throw;
        }

        // Return the task that represents the async operation
        return tcs.Task;
    }

অবশেষে, আমি নিম্নলিখিতগুলিও দরকারী পেয়েছি:

আমি এই প্রশ্নটি সারাক্ষণ জিজ্ঞাসা করি। এর অর্থ এই যে কোনও কোনও থ্রেড থাকা আবশ্যক যা বাহ্যিক সংস্থানগুলিতে আই / ও কলটিতে অবরুদ্ধ রয়েছে। সুতরাং, অ্যাসিঙ্ক্রোনাস কোড অনুরোধের থ্রেডকে মুক্ত করে, তবে কেবল সিস্টেমের অন্য থ্রেডের ব্যয়েই, ঠিক? না কোনভাবেই না. কেন অ্যাসিঙ্ক্রোনাস অনুরোধগুলি স্কেল হয় তা বোঝার জন্য, আমি অ্যাসিঙ্ক্রোনাস আই / ও কলটির একটি (সরলিকৃত) উদাহরণটি সন্ধান করব। ধরা যাক একটি অনুরোধের জন্য কোনও ফাইল লিখতে হবে। অনুরোধ থ্রেড অ্যাসিক্রোনাস রাইটিং পদ্ধতি কল করে। WritAsync বেস ক্লাস লাইব্রেরি (বিসিএল) দ্বারা প্রয়োগ করা হয়েছে এবং এর অ্যাসিনক্রোনাস I / O এর জন্য সমাপ্তি বন্দর ব্যবহার করে। সুতরাং, WritAsync কলটি অ্যাসিঙ্ক্রোনাস ফাইল রাইটিং হিসাবে ওএস-এ চলে গেছে। ওএস ড্রাইভার স্ট্যাকের সাথে যোগাযোগ করে, আই / ও অনুরোধ প্যাকেটে (আইআরপি) লেখার জন্য ডেটা বরাবর চলে যায়। এখানেই জিনিসগুলি আকর্ষণীয় হয়ে উঠেছে: যদি কোনও ডিভাইস ড্রাইভার তাত্ক্ষণিকভাবে কোনও আইআরপি হ্যান্ডেল করতে না পারে তবে এটি অবশ্যই এটি অবিচ্ছিন্নভাবে পরিচালনা করতে হবে। সুতরাং, ড্রাইভার ডিস্কটি লেখা শুরু করতে বলে এবং ওএসের কাছে একটি "মুলতুবি" প্রতিক্রিয়া দেয়। ওএস ছাত্রলীগের সেই "মুলতুবি" প্রতিক্রিয়াটি পাস করে এবং ছাত্রলীগ অনুরোধ হ্যান্ডলিং কোডটিতে একটি অসম্পূর্ণ কাজটি ফিরিয়ে দেয়। অনুরোধ-হ্যান্ডলিং কোডটি সেই কার্যটির জন্য অপেক্ষা করছে, যা সেই পদ্ধতি থেকে অন্য একটি অসম্পূর্ণ কাজটি প্রদান করে। অবশেষে, অনুরোধ-হ্যান্ডলিং কোডটি এএসপি.এনইটি-র কাছে অসম্পূর্ণ কাজটি শেষ করে এবং অনুরোধের থ্রেডটি থ্রেড পুলে ফিরে যাওয়ার জন্য মুক্ত হয়। অনুরোধ-হ্যান্ডলিং কোডটি সেই কার্যটির জন্য অপেক্ষা করছে, যা সেই পদ্ধতি থেকে অন্য একটি অসম্পূর্ণ কাজটি প্রদান করে। অবশেষে, অনুরোধ-হ্যান্ডলিং কোডটি এএসপি.এনইটি-র কাছে অসম্পূর্ণ কাজটি শেষ করে এবং অনুরোধের থ্রেডটি থ্রেড পুলে ফিরে যাওয়ার জন্য মুক্ত হয়। অনুরোধ-হ্যান্ডলিং কোডটি সেই কার্যটির জন্য অপেক্ষা করছে, যা সেই পদ্ধতি থেকে অন্য একটি অসম্পূর্ণ কাজটি প্রদান করে। অবশেষে, অনুরোধ-হ্যান্ডলিং কোডটি এএসপি.এনইটি-র কাছে অসম্পূর্ণ কাজটি শেষ করে এবং অনুরোধের থ্রেডটি থ্রেড পুলে ফিরে যাওয়ার জন্য মুক্ত হয়।

এএসপি.এনইটি তে অ্যাসিঙ্ক / ওয়েভের পরিচয়

যদি লক্ষ্যটি স্কেলেবিলিটি (প্রতিক্রিয়াশীলতার চেয়ে) উন্নত করা হয় তবে এটি সমস্তই বাহ্যিক আই / ও এর অস্তিত্বের উপর নির্ভর করে যা এটি করার সুযোগ দেয়।


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

সুতরাং আপনি থ্রেডপুল.কুইউ ইউজার ওয়ার্কআইটেম দিয়ে যা করেছেন তা টাস্ক.রুনের সাথে করা যেতে পারে, তাই না?
রাজ্জান

-1

অ্যাসিঙ্ক্রোনাস পদ্ধতিটি তৈরি করার একটি খুব সহজ উপায় হ'ল টাস্ক.ইয়েলড () পদ্ধতিটি ব্যবহার করা। এমএসডিএন যেমন বলেছে:

আপনি প্রত্যাশিত টাস্ক.ইয়েলড () ব্যবহার করতে পারেন; অ্যাসিঙ্ক্রোনাস পদ্ধতিতে পদ্ধতিটিকে অ্যাসিঙ্ক্রোনালি সম্পন্ন করতে বাধ্য করতে।

আপনার পদ্ধতির শুরুতে এটি Inোকান এবং এটি তখনই কলারের কাছে ফিরে আসবে এবং বাকী পদ্ধতিটি অন্য থ্রেডে সম্পূর্ণ করবে।

private async Task<DateTime> CountToAsync(int num = 1000)
{
    await Task.Yield();
    for (int i = 0; i < num; i++)
    {
        Console.WriteLine("#{0}", i);
    }
    return DateTime.Now;
}

উইনফর্মস অ্যাপ্লিকেশনটিতে বাকি পদ্ধতিটি একই থ্রেডে (ইউআই থ্রেড) সম্পূর্ণ হবে। Task.Yield()মামলা যে আপনার তা নিশ্চিত করার জন্য ফিরে চান তাদের জন্য প্রকৃতপক্ষে দরকারী, Taskঅবিলম্বে সৃষ্টি উপর সম্পন্ন করা হবে না।
থিওডর জৌলিয়াস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.