অ্যাসিঙ্ক পদ্ধতিটি সম্পূর্ণ হওয়ার জন্য কীভাবে অপেক্ষা করবেন?


138

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

private async void RequestToSendOutputReport(List<byte[]> byteArrays)
{
    foreach (byte[] b in byteArrays)
    {
        while (condition)
        {
            // we'll typically execute this code many times until the condition is no longer met
            Task t = SendOutputReportViaInterruptTransfer();
            await t;
        }

        // read some data from device; we need to wait for this to return
        RequestToGetInputReport();
    }
}

আমার কোডটি যখন লুপটির বাইরে চলে যায় তখন আমাকে ডিভাইস থেকে কিছু ডেটা পড়তে হবে। তবে, ডিভাইস এখনই প্রতিক্রিয়া জানাতে সক্ষম হচ্ছে না তাই আমার চালিয়ে যাওয়ার আগে এই কলটি ফিরে আসার জন্য অপেক্ষা করা দরকার wait এটি বর্তমানে বিদ্যমান থাকায়, অনুরোধটিগেটপুট রিপোর্ট () এইভাবে ঘোষিত হয়েছে:

private async void RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}

এটি মূল্যবান কিসের জন্য, getInputReportViaInterruptTransfer () এর ঘোষণাপত্রটি এর মতো দেখাচ্ছে:

internal async Task<int> GetInputReportViaInterruptTransfer()

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

আমি যে আচরণটি দেখছি তা কি কেউ স্পষ্ট করতে পারেন?

উত্তর:


131

এড়ানো async voidTaskপরিবর্তে আপনার পদ্ধতিগুলি ফিরে আসুন void। তাহলে আপনি awaitতাদের পারেন ।

এটার মত:

private async Task RequestToSendOutputReport(List<byte[]> byteArrays)
{
    foreach (byte[] b in byteArrays)
    {
        while (condition)
        {
            // we'll typically execute this code many times until the condition is no longer met
            Task t = SendOutputReportViaInterruptTransfer();
            await t;
        }

        // read some data from device; we need to wait for this to return
        await RequestToGetInputReport();
    }
}

private async Task RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}

1
খুব সুন্দর, ধন্যবাদ. আমি অনুরূপ ইস্যুতে আমার মাথা আঁচড়াচ্ছিলাম এবং পার্থক্যটি ছিল আপনি যেমন বলেছিলেন ঠিক তেমন পরিবর্তন voidকরা Task
জেরেমি

8
এটি একটি গৌণ বিষয়, তবে কনভেনশনটি অনুসরণ করতে উভয় পদ্ধতিরই এসিঙ্কের নাম যুক্ত করা উচিত, যেমন রিকোয়েস্টটোগেটআইপুট রিপোর্টারসিন্যাক ()
টিমটাম

6
এবং যদি কলকারী মূল কাজ হয়?
প্রতীক

14
@ সিমবায়ান্ট: তারপরে ব্যবহার করুনGetAwaiter().GetResult()
স্টিফেন ক্লিয়ারি

4
@ আহমদসালাহ Taskপদ্ধতিটি কার্যকর করার জন্য প্রতিনিধিত্ব করে - সুতরাং returnমানগুলি রাখা হয় Task.Resultএবং ব্যতিক্রমগুলি স্থাপন করা হয় Task.Exception। সহ void, সংকলকটির ব্যতিক্রমের কোথাও নেই, তাই তারা কেবল একটি থ্রেড পুলের থ্রেডে পুনরায় উত্থিত হয়।
স্টিফেন ক্লিয়ারি

229

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

আপনার প্রশ্নের শিরোনামে নির্দিষ্ট প্রশ্নের উত্তর হ'ল কোনও asyncপদ্ধতির রিটার্ন মান (যা টাইপ হওয়া উচিত Taskবা Task<T>) উপযুক্ত Waitপদ্ধতিতে কল করে ব্লক করা :

public static async Task<Foo> GetFooAsync()
{
    // Start asynchronous operation(s) and return associated task.
    ...
}

public static Foo CallGetFooAsyncAndWaitOnResult()
{
    var task = GetFooAsync();
    task.Wait(); // Blocks current thread until GetFooAsync task completes
                 // For pedagogical use only: in general, don't do this!
    var result = task.Result;
    return result;
}

এই কোড স্নিপেটে, অ্যাসিক্রোনাস পদ্ধতির চারপাশে CallGetFooAsyncAndWaitOnResultএকটি সিঙ্ক্রোনাস র‍্যাপার GetFooAsync। তবে, এই প্যাটার্নটি বেশিরভাগ অংশের জন্য এড়ানো হবে কারণ এটি অ্যাসিক্রোনাস অপারেশনের সময়কালে পুরো থ্রেড পুলের থ্রেডটিকে ব্লক করবে। এপিআই দ্বারা প্রকাশিত বিভিন্ন অ্যাসিক্রোনাস মেকানিজমগুলির এটির অদক্ষ ব্যবহার যা তাদের সরবরাহের জন্য প্রচুর চেষ্টা করে।

এ উত্তর "অপেক্ষায় রয়েছেন" Call শেষ হওয়ার জন্য অপেক্ষা করে না বিভিন্ন, আরো বিস্তারিত করেনি, এই কীওয়ার্ড ব্যাখ্যা।

এদিকে, হোল্ডস সম্পর্কে @ স্টিফেন ক্লিয়ারির গাইডেন্স async voidHttp://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-thods/ এবং https://jaylee.org/archive/ এ কেন পাওয়া যাবে তার জন্য অন্যান্য দুর্দান্ত ব্যাখ্যা 2012/07/08 / সি-ধারালো-ASYNC-টিপস-এন্ড-ট্রিকস-অংশ-2-ASYNC-void.html


18
আমি await"অ্যাসিনক্রোনাস ওয়েট" হিসাবে ভাবতে (এবং কথা বলা) দরকারী মনে করি - এটি পদ্ধতিটি (যদি প্রয়োজন হয়) তবে থ্রেডকে অবরুদ্ধ করে না । সুতরাং এটি RequestToSendOutputReport"অপেক্ষার" বিষয়ে কথা বলা বুদ্ধিমান হয়ে RequestToGetInputReportযায় যদিও এটি কোনও অবরুদ্ধ অপেক্ষা নয়।
স্টিফেন ক্লিয়ারি

@ রিচার্ড কুক - অতিরিক্ত ব্যাখ্যা দেওয়ার জন্য আপনাকে অনেক ধন্যবাদ!
বিএমটি 22033

10
এটি অবশ্যই গ্রহণযোগ্য উত্তর হওয়া উচিত, যেহেতু এটি প্রকৃত প্রশ্নের আরও স্পষ্টভাবে উত্তর দেয় (যেমন কীভাবে একটি অ্যাসিঙ্ক পদ্ধতিতে থ্রেড-ওয়াইন ব্লক করা যায়)।
csvan

টাস্ক সম্পূর্ণ না হওয়া অবধি সেরা সমাধান অপেক্ষা অপেক্ষারত অপসারণ = টাস্ক.রুন (অ্যাসিঙ্ক () => {প্রত্যাশা আপনার মেঠোদ ();}); ফলাফল;
রাম চিত্তলা

70

টাস্ক সম্পন্ন না হওয়া পর্যন্ত অ্যাসিনমেথোদ অপেক্ষা করার সেরা সমাধান

var result = Task.Run(async() => await yourAsyncMethod()).Result;

15
বা এটি আপনার অ্যাসিঙ্ক "শূন্য" এর জন্য: টাস্ক.আরুন (অ্যাসিঙ্ক () => your আপনার অ্যাসিঙ্কমিথড ();}) অপেক্ষা করুন; অপেক্ষা করুন ();
জিও হার্নেক

1
আপনারAncncMethod () এর ফলাফল কী?
জাস্টিন জে স্টার্ক

1
টাস্কটি সম্পাদন শেষ না হওয়া পর্যন্ত কেবলমাত্র .সম্পর্কিত সম্পত্তি অ্যাক্সেস করা আসলে অপেক্ষা করে না। আসলে, আমি বিশ্বাস করি কোনও কাজ শেষ হওয়ার আগে যদি এটি ডাকা হয় তবে এটি একটি ব্যতিক্রম ছুঁড়ে দেয়। আমি মনে করি এটি কোনও টাস্ক.রুন () কলটিতে মোড়ানোর সুবিধাটি হ'ল নীচে, যেমন রিচার্ড কুক উল্লেখ করেছেন, "অপেক্ষা" আসলে কোনও কাজ শেষ হওয়ার অপেক্ষা করে না, তবে একটি ওয়েট () কল ব্যবহার করে আপনার পুরো থ্রেড পুলটি ব্লক করে দেয় । এটি আপনাকে (সুসংগতভাবে) পৃথক থ্রেডে একটি অ্যাসিঙ্ক পদ্ধতি চালাতে সহায়তা করে। সামান্য বিভ্রান্তিকর, কিন্তু এটি আছে।
লুকাস লেব্ল্যাঙ্ক

সেখানে ফলাফলটি ছুঁড়ে দেওয়া ঠিক হয়েছে, আমার যা প্রয়োজন ছিল
গেরি

দ্রুত অনুস্মারক ইসিএমএ 7 বৈশিষ্ট্যযুক্ত অ্যাসিঙ্ক () বা প্রাক-ইসিএমএ 7 পরিবেশে অভ্যাসের জন্য অপেক্ষা করবে।
এমবোটেট

0

এখানে একটি পতাকা ব্যবহার করে কাজ করা হবে:

//outside your event or method, but inside your class
private bool IsExecuted = false;

private async Task MethodA()
{

//Do Stuff Here

IsExecuted = true;
}

.
.
.

//Inside your event or method

{
await MethodA();

while (!isExecuted) Thread.Sleep(200); // <-------

await MethodB();
}

-1

টাস্ক শেষ না হওয়া পর্যন্ত অপেক্ষা () অপেক্ষা করুন

GetInputReportViaInterruptTransfer().Wait();


এটি বর্তমান থ্রেডকে ব্লক করে। সুতরাং এটি সাধারণত খারাপ কাজ।
খাঁটি.ক্রোম

-4

আসলে আমি IAsyncAction ফিরিয়ে ফাংশনগুলির জন্য এটি আরও সহায়ক বলে মনে করি।

            var task = asyncFunction();
            while (task.Status == AsyncStatus.Completed) ;

-5

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

public async Task AnAsyncMethodThatCompletes()
{
    await SomeAsyncMethod();
    DoSomeMoreStuff();
    await Task.Factory.StartNew(() => { }); // <-- This line here, at the end
}

await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")

ডাউনভোটার্স, ব্যাখ্যা করতে যত্ন, যেমন আমি উত্তরে জিজ্ঞাসা করেছি? কারণ এটি যতদূর আমি জানি ঠিক তত ভাল কাজ করে ...
জেরের

3
সমস্যা যে একমাত্র উপায় আপনি কি করতে পারেন await+ + Console.WriteLineএটি একটি হয়ে উঠছে হয় Taskযা দুই মধ্যে নিয়ন্ত্রণ মানেনা। সুতরাং আপনার 'সমাধান' পরিণামে একটি উত্পন্ন করবে Task<T>, যা সমস্যার সমাধান করবে না। এরকম একটি Task.Waitহবে আসলে (অচলাবস্থা সম্ভাবনার ইত্যাদি সহ) প্রক্রিয়াকরণের বন্ধ করে দেব। অন্য কথায়, awaitআসলে অপেক্ষা করবেন না, এটি কেবলমাত্র একটি Task
অবিচ্ছিন্নভাবে কার্যকরযোগ্য অংশগুলিকে এককভাবে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.