সি # তে "প্রত্যাবর্তনের অপেক্ষার" উদ্দেশ্য কী?


251

লেখার পদ্ধতি এমন যেখানে আছে এমন কোনও দৃশ্য আছে :

public async Task<SomeResult> DoSomethingAsync()
{
    // Some synchronous code might or might not be here... //
    return await DoAnotherThingAsync();
}

এর পরিবর্তে:

public Task<SomeResult> DoSomethingAsync()
{
    // Some synchronous code might or might not be here... //
    return DoAnotherThingAsync();
}

কোন মানে হবে?

return awaitযখন আপনি সরাসরি Task<T>অভ্যন্তরীণ DoAnotherThingAsync()প্রার্থনা থেকে ফিরে আসতে পারেন তখন কেন কনস্ট্রাক্ট ব্যবহার করবেন ?

আমি return awaitঅনেক জায়গায় কোডটি দেখতে পাচ্ছি , আমার মনে হয় আমি হয়ত কিছু মিস করেছি। তবে যতদূর আমি বুঝতে পারি, এক্ষেত্রে async / অপেক্ষার কীওয়ার্ড ব্যবহার না করা এবং সরাসরি টাস্ক ফিরিয়ে দেওয়া কার্যত সমতুল্য হবে। অতিরিক্ত awaitস্তরের অতিরিক্ত ওভারহেড যুক্ত করবেন কেন ?


2
আমি মনে করি আপনি এটিকে দেখার একমাত্র কারণ হ'ল লোকেরা অনুকরণের মাধ্যমে শিখে এবং সাধারণত (যদি তাদের প্রয়োজন না হয়) তবে তারা সন্ধান করতে পারে এমন সহজ সমাধানটি ব্যবহার করে use সুতরাং লোকেরা সেই কোডটি দেখে, সেই কোডটি ব্যবহার করে, তারা দেখেছে এটি কাজ করে এবং এখন থেকে, তাদের পক্ষে এটি করা সঠিক উপায় ... এটির ক্ষেত্রে অপেক্ষা করার কোনও লাভ নেই
ফ্যাবিও মার্কোলোনি

7
কমপক্ষে একটি গুরুত্বপূর্ণ পার্থক্য রয়েছে: ব্যতিক্রম প্রচার
নসরটিটিও

1
আমি এটি বুঝতে পারি না, এ পুরো ধারণাটি মোটেও বুঝতে পারছি না, কোনও ধারণা নেই। আমি যদি শিখেছি যে কোনও পদ্ধতিতে রিটার্ন টাইপ রয়েছে, এটির কি রিটার্ন কীওয়ার্ড থাকা উচিত, এটি কি সি # ভাষার নিয়ম নয়?
মনস্টো

@ মমস্ট্রো ওপির প্রশ্নের কি রিটার্ন স্টেটমেন্ট আছে?
ডেভিড ক্লেম্পফনার

উত্তর:


189

যখন returnসাধারণ পদ্ধতিতে এবং পদ্ধতিতে আলাদাভাবে আচরণ করা return awaitহয় তখন একটি ছদ্মবেশী কেস রয়েছে async: যখন using(বা আরও সাধারণভাবে কোনও ব্লকের কোনও return awaitসাথে try) মিলিত হয় ।

একটি পদ্ধতির এই দুটি সংস্করণ বিবেচনা করুন:

Task<SomeResult> DoSomethingAsync()
{
    using (var foo = new Foo())
    {
        return foo.DoAnotherThingAsync();
    }
}

async Task<SomeResult> DoSomethingAsync()
{
    using (var foo = new Foo())
    {
        return await foo.DoAnotherThingAsync();
    }
}

প্রথম পদ্ধতি হবে বস্তুর যত তাড়াতাড়ি পদ্ধতি আয়, আগে এটি আসলে সমাপ্ত যা সম্ভবত দীর্ঘ। এর অর্থ হ'ল প্রথম সংস্করণটি সম্ভবত বগি (কারণ খুব তাড়াতাড়ি নিষ্পত্তি হবে), দ্বিতীয় সংস্করণটি ঠিকঠাকভাবে কাজ করবে।Dispose()FooDoAnotherThingAsync()Foo


4
সম্পূর্ণতার জন্য, প্রথম ক্ষেত্রে আপনার ফিরে foo.DoAnotherThingAsync().ContinueWith(_ => foo.Dispose());
আসা

7
@ গর্ড যা কাজ করে না, Dispose()ফিরে আসে void। আপনার মতো কিছু লাগবে return foo.DoAnotherThingAsync().ContinueWith(t -> { foo.Dispose(); return t.Result; });। আপনি যখন দ্বিতীয় বিকল্পটি ব্যবহার করতে পারবেন তখন কেন আপনি তা করবেন তা আমি জানি না।
সুইভ

1
@ স্পিক আপনি ঠিক বলেছেন, এটি আরও বেশি হওয়া উচিত { var task = DoAnotherThingAsync(); task.ContinueWith(_ => foo.Dispose()); return task; }। ব্যবহারের কেসটি খুব সহজ: আপনি নেট নেট 4.0.০ এ থাকলে (বেশিরভাগের মতো), আপনি এখনও এইভাবে এসিঙ্ক কোডটি লিখতে পারেন যা ৪.৫ টি অ্যাপ্লিকেশন থেকে খুব সুন্দরভাবে কাজ করবে।
ঘোর্ড

2
@ গর্ড যদি আপনি। নেট 4.0 এ থাকেন এবং আপনি অ্যাসিঙ্ক্রোনাস কোডটি লিখতে চান তবে আপনার সম্ভবত মাইক্রোসফট.বিসিএল.এএনসিঙ্ক ব্যবহার করা উচিত । এবং আপনার কোডটি Fooকেবলমাত্র রিটার্ন Taskসম্পূর্ণ হওয়ার পরে তা নিষ্পত্তি করে , যা আমি পছন্দ করি না, কারণ এটি অকারণে সম্মতির পরিচয় দেয়।
সুইভ

1
@ এসভিক আপনার কোডটি টাস্কটি শেষ না হওয়া পর্যন্ত অপেক্ষা করে। এছাড়াও, KB2468871 এর উপর নির্ভরশীলতা এবং উপযুক্ত 4.5 অ্যাসিঙ্ক কোড সহ .NET 4.0 অ্যাসিঙ্ক কোডবেস ব্যবহার করার সময় দ্বন্দ্বের কারণে মাইক্রোসফ্ট.বিসিএল.এসিঙ্ক আমার পক্ষে অকার্যকর।
ঘোর্ড

93

আপনার যদি প্রয়োজন না হয় async(যেমন, আপনি Taskসরাসরি ফেরত দিতে পারেন ), তবে ব্যবহার করবেন না async

কিছু পরিস্থিতি রয়েছে যেখানে return awaitদরকারী, যেমন যদি আপনার কাছে দুটি অ্যাসিনক্রোনাস অপারেশন থাকে:

var intermediate = await FirstAsync();
return await SecondAwait(intermediate);

আরো জানার জন্য asyncকর্মক্ষমতা, স্টিফেন Toub দেখি দুটিই MSDN নিবন্ধ এবং ভিডিও বিষয়ে।

আপডেট: আমি একটি ব্লগ পোস্ট লিখেছি যা আরও বিস্তারিতভাবে যায়।


13
awaitদ্বিতীয় ক্ষেত্রে কেন এটি কার্যকর তা আপনি একটি ব্যাখ্যা যুক্ত করতে পারেন ? কেন করবেন না return SecondAwait(intermediate);?
ম্যাট স্মিথ

2
আমি ম্যাট হিসাবে একই প্রশ্ন, return SecondAwait(intermediate);সেই ক্ষেত্রেও লক্ষ্য অর্জন করতে হবে না ? আমি return awaitএখানেও অপ্রয়োজনীয় বলে মনে করি ...
TX_

23
@ ম্যাটস্মিথ এটি সংকলন করবে না। আপনি যদি awaitপ্রথম লাইনে ব্যবহার করতে চান তবে আপনাকে এটি দ্বিতীয় একটিতেও ব্যবহার করতে হবে।
সুইভ

2
@ কেটায়স আমি নিশ্চিত "ওভারহেড তাদের সমান্তরাল করে পরিচয় করিয়েছি" এর অর্থ কী, তবে asyncসংস্করণটি আপনার সিঙ্ক্রোনাস সংস্করণের চেয়ে কম সংস্থান (থ্রেড) ব্যবহার করবে ।
সুইভ

4
@ টমলিন্ট এটি সত্যিই সংকলন করে না। এর রিটার্ন টাইপ ধরে নেওয়া যাক SecondAwaitহল `স্ট্রিং, ত্রুটি বার্তাটি আছে:" CS4016: যেহেতু এই একটি ASYNC পদ্ধতি, রিটার্ন অভিব্যক্তি টাইপ 'STRING' বদলে 'টাস্ক <স্ট্রিং>' হওয়া আবশ্যক "।
সোভিক

23

awaitপূর্ববর্তী কোডটিতে অন্য কিছু রয়েছে বা আপনি যদি কোনও উপায়ে ফলাফলটি ফেরত দেওয়ার আগে কারচুপি করে থাকেন তবে আপনি এটি করতে চান reason এটি ঘটতে পারে এমন আরেকটি উপায় হ'ল try/catchব্যতিক্রমগুলি কীভাবে পরিচালনা করা হয় তা পরিবর্তিত করে। আপনি যদি এটির কিছু না করে থাকেন তবে আপনি সঠিক, পদ্ধতিটি তৈরির ওভারহেড যুক্ত করার কোনও কারণ নেই async


4
স্টিফেনস উত্তর হিসাবে, আমি বুঝতে পারছি না কেন return awaitপ্রয়োজন হতে (পরিবর্তে শুধু সন্তান আবাহন কাজটি ফেরার এর) এমনকি যদি সেখানে তার আগে কোডে কিছু অন্যান্য অপেক্ষায় রয়েছেন হয় । আপনি দয়া করে ব্যাখ্যা দিতে পারেন?
TX_

10
@ টিএক্স_ আপনি যদি অপসারণ করতে চান asyncতবে আপনি কীভাবে প্রথম কাজের অপেক্ষায় থাকবেন? আপনি পদ্ধতিটি চিহ্নিত করতে হবে asyncযেন আপনি কোনও অপেক্ষারত ব্যবহার করতে চান । যদি পদ্ধতিটি চিহ্নিত করা হয় asyncএবং কোডটিতে আপনার আগেরটি রয়েছে await, তবে awaitএটি সঠিক ধরণের হওয়ার জন্য আপনাকে দ্বিতীয় অ্যাসিঙ্ক অপারেশন করতে হবে। আপনি যদি সবে সরিয়ে ফেলে থাকেন awaitতবে এটি সংকলন করবে না কারণ রিটার্নের মানটি সঠিক ধরণের হবে না। পদ্ধতিটি যেহেতু asyncফলাফল সর্বদা একটি কার্যে আবৃত থাকে।
পরিবেশন করুন

11
@ নোসরটিও দু'জনের চেষ্টা করুন। প্রথম সংকলন। দ্বিতীয়টি না। ত্রুটি বার্তা আপনাকে সমস্যাটি বলবে। আপনি সঠিক ধরণের ফিরে আসবেন না। যখন কোনও asyncপদ্ধতিতে আপনি কোনও কাজ ফিরে না পান, আপনি সেই কার্যটির ফলাফলটি ফিরিয়ে দেন যা পরে মোড়ানো হবে।
শে

3
@ সার্ভি, অবশ্যই - আপনি ঠিক বলেছেন। পরবর্তী ক্ষেত্রে আমরা Task<Type>স্পষ্টভাবে ফিরে আসব , যখন asyncফেরতের নির্দেশ দেয় Type(যা সংকলক নিজেই রূপান্তরিত করে Task<Type>)।
নসরাটিও

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

17

ফলাফলের জন্য আপনার অপেক্ষা করতে হতে পারে এমন আরও একটি মামলা হ'ল:

async Task<IFoo> GetIFooAsync()
{
    return await GetFooAsync();
}

async Task<Foo> GetFooAsync()
{
    var foo = await CreateFooAsync();
    await foo.InitializeAsync();
    return foo;
}

এই ক্ষেত্রে GetIFooAsync()অবশ্যই ফলাফলটির জন্য অপেক্ষা করতে হবে GetFooAsyncকারণ Tদুটি পদ্ধতির মধ্যে প্রকারভেদ পৃথক এবং Task<Foo>সরাসরি অর্পণযোগ্য নয় Task<IFoo>। কিন্তু আপনি যদি ফলাফলের জন্য অপেক্ষা করুন, এটা ঠিক হয়ে Fooযা হয় সরাসরি হস্তান্তরযোগ্য IFoo। তারপরে অ্যাসিঙ্ক পদ্ধতিটি কেবল ফলাফলটির ভিতরেই প্রবেশ করে Task<IFoo>এবং আপনি চলে যান।


1
সম্মত হোন, এটি সত্যই বিরক্তিকর - আমি বিশ্বাস করি যে অন্তর্নিহিত কারণটি Task<>হ'ল অদম্য।
স্টুয়ার্টএলসি

7

অন্যথায় সহজ "থঙ্ক" পদ্ধতিটি অ্যাসিঙ্ক তৈরি করা মেমরির মধ্যে একটি অ্যাসিঙ্ক স্টেট মেশিন তৈরি করে যেখানে অ-অ্যাসিঙ্কটি তা করে না। যদিও এটি প্রায়শই লোকেদের অ-অ্যাসিঙ্ক সংস্করণটি ব্যবহার করার দিকে নির্দেশ করতে পারে কারণ এটি আরও দক্ষ (যা সত্য) এর অর্থ এটিও হ'ল যে একটি ঝুলন্ত ঘটনার ক্ষেত্রে আপনার কাছে কোনও প্রমাণ নেই যে "পদ্ধতিটি" রিটার্ন / ধারাবাহিকতা স্ট্যাকের সাথে জড়িত is যা মাঝে মাঝে হ্যাং বুঝতে আরও অসুবিধা তৈরি করে।

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


6

আপনি যদি প্রত্যাবর্তনের অপেক্ষায় না ব্যবহার করেন তবে আপনি ডিবাগ করার সময় বা এটি ব্যতিক্রম লগগুলিতে মুদ্রিত হওয়ার পরে আপনার স্ট্যাকের ট্রেস নষ্ট করতে পারেন।

আপনি যখন টাস্কটি ফিরিয়ে দেন, পদ্ধতিটি তার উদ্দেশ্যটি পূরণ করে এবং কল স্ট্যাকের বাইরে চলে যায়। আপনি যখন ব্যবহার return awaitকরবেন তখন এটি কল স্ট্যাকের মধ্যে রেখে যাচ্ছেন।

উদাহরণ স্বরূপ:

অপেক্ষা করার সময় কল স্ট্যাক: বি => বি থেকে টাস্কটি সি থেকে টাস্কের জন্য অপেক্ষা করা

অপেক্ষা না করার সময় কল স্ট্যাক : সি থেকে টাস্কের জন্য অপেক্ষা করা, যা বি ফিরে এসেছে।


2

এটিও আমাকে বিভ্রান্ত করে এবং আমি অনুভব করি যে পূর্ববর্তী উত্তরগুলি আপনার প্রকৃত প্রশ্নটিকে উপেক্ষা করেছে:

আপনি যখন অভ্যন্তরীণ DoAnotherTingAsync () অনুরোধ থেকে সরাসরি টাস্কটি ফিরিয়ে দিতে পারবেন তখন কেন রিটার্ন অপেক্ষার জন্য ব্যবহার করবেন?

ভাল কখনও কখনও আপনি আসলে একটি চান Task<SomeType>, কিন্তু বেশিরভাগ সময় আপনি আসলে একটি উদাহরণ চান SomeType, যা, টাস্ক থেকে ফলাফল।

আপনার কোড থেকে:

async Task<SomeResult> DoSomethingAsync()
{
    using (var foo = new Foo())
    {
        return await foo.DoAnotherThingAsync();
    }
}

সিনট্যাক্সের সাথে অপরিচিত কোনও ব্যক্তি (উদাহরণস্বরূপ, আমি) মনে করতে পারি যে এই পদ্ধতিটি একটি ফেরত আসা উচিত Task<SomeResult>, তবে যেহেতু এটি চিহ্নিত রয়েছে async, তার অর্থ এটির আসল প্রত্যাবর্তনের ধরণ SomeResult। আপনি যদি কেবলমাত্র ব্যবহার করেন return foo.DoAnotherThingAsync(), আপনি একটি টাস্ক ফিরিয়ে দিবেন যা সংকলন করবে না। সঠিক উপায় হ'ল কার্যের ফলাফলটি ফিরিয়ে দেওয়া, তাই return await


1
"আসল রিটার্ন টাইপ"। অঁ্যা? async / প্রতীক্ষা রিটার্নের ধরণ পরিবর্তন করে না। আপনার উদাহরণে var task = DoSomethingAsync();আপনাকে একটি কার্য দেবে, নাT
জুতার

2
@ শু আমি নিশ্চিত যে আমি async/awaitবিষয়টি ভালভাবে বুঝতে পেরেছি না । আমার বোঝার জন্য, উভয় কাজ করার Task task = DoSomethingAsync()সময় Something something = await DoSomethingAsync()। প্রথমটি আপনাকে কার্যটি যথাযথ দেয়, দ্বিতীয়টি awaitকীওয়ার্ডের কারণে , কার্যটি সম্পূর্ণ হওয়ার পরে আপনাকে ফলাফলটি দেয় । আমি, উদাহরণস্বরূপ, পারে Task task = DoSomethingAsync(); Something something = await task;
হেলটনবাইকার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.