সমস্ত সার্ভার-সাইড কোডের জন্য কনফিগারআউট কল করতে সেরা অনুশীলন


561

যখন আপনার সার্ভার-সাইড কোড রয়েছে (যেমন কিছু ApiController) এবং আপনার ফাংশনগুলি অবিচ্ছিন্ন - তাই তারা ফিরে আসে Task<SomeObject>- আপনি কল করার ফাংশনের জন্য অপেক্ষা করা কোনও সময়ই কি সেরা অনুশীলন হিসাবে বিবেচিত হবে ConfigureAwait(false)?

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

আমি নীচে যা বলছি তার একটি উদাহরণ লিখেছি:

public class CustomerController : ApiController
{
    public async Task<Customer> Get(int id)
    {
        // you are on a particular thread here
        var customer = await SomeAsyncFunctionThatGetsCustomer(id).ConfigureAwait(false);

        // now you are on a different thread!  will that cause problems?
        return customer;
    }
}

উত্তর:


627

আপডেট: ASP.NET কোর একটি নেইSynchronizationContext । আপনি যদি এএসপি.নেট কোরে থাকেন তবে আপনি ব্যবহার করেন ConfigureAwait(false)বা না করেন তা বিবেচ্য নয়।

ASP.NET "পূর্ণ" বা "ক্লাসিক" বা যাই হোক না কেন, এই উত্তরটির বাকি অংশ এখনও প্রযোজ্য।

মূল পোস্ট (নন-কোর এএসপি.এনইটি জন্য):

এএসপি.এনইটি টিমের এই ভিডিওটিতে এএসপি.এনইটি ব্যবহারের সর্বোত্তম তথ্য রয়েছে async

আমি পড়েছিলাম এটি থ্রেড প্রসঙ্গগুলি মূল থ্রেড প্রসঙ্গে ফিরে যেতে হবে না কারণ এটি আরও অভিনয়যোগ্য।

এটি ইউআই অ্যাপ্লিকেশনগুলির সাথে সত্য, যেখানে কেবলমাত্র একটি ইউআই থ্রেড রয়েছে যা আপনাকে "সিঙ্ক" করতে হবে।

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

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

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

প্রকৃতপক্ষে, কেবল একটি করছেন এটি awaitকরতে পারে। আপনার asyncপদ্ধতিটি হিট হয়ে গেলে await, পদ্ধতিটি অবরুদ্ধ থাকে তবে থ্রেড থ্রেড পুলে ফিরে আসে। পদ্ধতিটি চালিয়ে যাওয়ার জন্য প্রস্তুত হলে, থ্রেড পুল থেকে যে কোনও থ্রেড ছিনিয়ে নেওয়া হয় এবং পদ্ধতিটি পুনরায় শুরু করতে ব্যবহৃত হয়।

একমাত্র পার্থক্য ConfigureAwaitএএসপি.নেটে যে পদ্ধতিটি পুনরায় শুরু করার সময় সেই থ্রেডটি অনুরোধের প্রসঙ্গে প্রবেশ করে কিনা।

আমার এমএসডিএন নিবন্ধেSynchronizationContext এবং আমার asyncইন্ট্রো ব্লগ পোস্টে আমার আরও পটভূমি তথ্য রয়েছে ।


23
থ্রেড-লোকাল স্টোরেজ প্রবাহিত হয় না কোনও প্রসঙ্গে । HttpContext.Currentএএসপি.এনইটি দ্বারা প্রবাহিত হয় SynchronizationContext, যা আপনি যখন ডিফল্টরূপে প্রবাহিত হন awaitতবে তা প্রবাহিত হয় না ContinueWith। OTOH, ফাঁসি প্রসঙ্গ (নিরাপত্তা সীমাবদ্ধতা সহ) প্রসঙ্গ মাধ্যমে C # এর CLR উল্লেখ করা হয়, এবং এটি করা হয় উভয় দ্বারা নির্গত ContinueWithএবং await(এমনকি যদি আপনি ব্যবহার ConfigureAwait(false))।
স্টিফেন ক্লিয়ারি

65
এটি কি দুর্দান্ত হবে না যদি কনফিগারওয়েটের (মিথ্যা) জন্য সি # এর স্থানীয় ভাষার সমর্থন ছিল? 'অপেক্ষা' এর মতো কিছু (কোনও প্রসঙ্গে অপেক্ষা করবেন না)। সর্বত্র একটি পৃথক পদ্ধতি কল টাইপ করা বেশ বিরক্তিকর। :)
নাথানএলডেনসআর 8:38

19
@ নাথান অ্যালডেনএসআর: এটি নিয়ে বেশ আলোচনা হয়েছিল। একটি নতুন কীওয়ার্ডের সমস্যাটি হ'ল ConfigureAwaitআপনি যখন কাজের জন্য অপেক্ষা করছেন তখন কেবল তখনই তা বোধগম্য হয় , যেখানে awaitকোনও "প্রতীক্ষিত" কাজ করে। বিবেচিত অন্যান্য বিকল্পগুলি হ'ল: লাইব্রেরিতে থাকলে ডিফল্ট আচরণের প্রসঙ্গটি বাতিল করা উচিত? বা ডিফল্ট প্রসঙ্গ আচরণের জন্য একটি সংকলক সেটিংস আছে? এই দুটিই প্রত্যাখ্যান করা হয়েছিল কারণ কেবল কোডটি পড়া এবং এটি কী করে তা বলা শক্ত।
স্টিফেন ক্লিয়ারি

10
@ আনশুলনিগাম: যে কারণে নিয়ামক পদক্ষেপগুলি তাদের প্রসঙ্গে প্রয়োজন context তবে বেশিরভাগ পদ্ধতিগুলি যে ক্রিয়াগুলি কল করে না।
স্টিফেন ক্লিয়ারি

14
@ জোনাথনরোডার: সাধারণভাবে বলতে গেলে আপনার / / বেসড অচলাবস্থা ConfigureAwait(false)এড়ানো উচিত নয় কারণ এএসপি.নেটে আপনি প্রথমে / ব্যবহার করা উচিত নয় ।ResultWaitResultWait
স্টিফেন ক্লিয়ারি

131

আপনার প্রশ্নের সংক্ষিপ্ত উত্তর: না, আপনি ConfigureAwait(false)আবেদন স্তরের মতো কল করা উচিত নয় ।

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

ConfigureAwaitপদ্ধতির গুরুত্ব সম্পর্কে আমার এখানে আরও বিস্তারিত ব্যাখ্যা দেওয়া হয়েছে (আমার ব্লগ পোস্টের একটি উদ্ধৃতি):

আপনি অপেক্ষা করার কীওয়ার্ড সহ কোনও পদ্ধতির অপেক্ষায় থাকাকালীন, সংকলকটি আপনার পক্ষে কোডের গোছা তৈরি করে। এই ক্রিয়াকলাপের অন্যতম উদ্দেশ্য হ'ল ইউআই (বা প্রধান) থ্রেডের সাথে সিঙ্ক্রোনাইজেশন পরিচালনা করা। এই বৈশিষ্ট্যের মূল উপাদানটি হ'ল SynchronizationContext.Currentবর্তমান থ্রেডের জন্য সিঙ্ক্রোনাইজেশন প্রসঙ্গে। SynchronizationContext.Currentআপনি যে পরিবেশে রয়েছেন তার উপর নির্ভর করে জনবহুল। GetAwaiterটাস্কের পদ্ধতিটি সন্ধান করে SynchronizationContext.Current। যদি বর্তমান সিঙ্ক্রোনাইজেশন প্রসঙ্গটি শূন্য না হয় তবে সেই প্রত্যাশীতে যে ধারাবাহিকতাটি পাস করা হয় তা সেই সিঙ্ক্রোনাইজেশন প্রসঙ্গে ফিরে আসবে।

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

এছাড়াও, আপনার জন্য এখানে দুটি দুর্দান্ত নিবন্ধ রয়েছে যা আপনার প্রশ্নের জন্য হুবহু:

শেষ অবধি, লুসিয়ান উইশিকের ঠিক এই বিষয়টিতে একটি দুর্দান্ত সংক্ষিপ্ত ভিডিও রয়েছে : অ্যাসিঙ্ক লাইব্রেরি পদ্ধতিতে টাস্ক ব্যবহারের বিষয়টি বিবেচনা করা উচিত on কনফিগুরেএয়েট (মিথ্যা)

আশাকরি এটা সাহায্য করবে.


2
"টাস্কের গেটএইয়েটার পদ্ধতিটি সিঙ্ক্রোনাইজেশন কনটেক্সট জন্য সন্ধান করে urrent বর্তমান sy - আমি এই ধারণাটি পেয়ে যাচ্ছি যে আপনি বলার চেষ্টা করছেন যে Taskএটি পেতে স্ট্যাকটি হাঁটে SynchronizationContext, যা ভুল। SynchronizationContextথেকে কল করার আগে ধরলাম হয় Taskএবং তারপর কোড বাকি অব্যাহত হয় SynchronizationContextযদি SynchronizationContext.Currentনাল নয়।
ক্যাস্পারনিউ

1
@ ক্যাস্পারওন আমি একই কথা বলার ইচ্ছা নিয়েছি।
টগবার্ক

8
ক্লারির SynchronizationContext.Currentসমস্ত লাইব্রেরিতে Task.Run()লেখার পরিবর্তে গ্রন্থাগারটি কল করা বা এটি পরিষ্কার হওয়া / বা লাইব্রেরিটি কল করা উচিত কিনা তা নিশ্চিত করা দায়বদ্ধতার দায়িত্ব হওয়া উচিত নয় .ConfigureAwait(false)?
বিনকি

1
@ বিঙ্কি - অন্যদিকে: (1) সম্ভবত কোনও অ্যাপ্লিকেশনটিতে একটি গ্রন্থাগার ব্যবহৃত হয়, সুতরাং অ্যাপ্লিকেশনগুলিকে সহজ করার জন্য গ্রন্থাগারে এক সময় চেষ্টা করা ব্যয়বহুল; (২) সম্ভবত গ্রন্থাগারের লেখক জানেন যে তিনি এমন কোড লিখেছেন যা মূল প্রসঙ্গে চালিয়ে যাওয়ার প্রয়োজন নেই, যা তিনি সেগুলির দ্বারা প্রকাশ করেছেন .ConfigureAwait(false)। সম্ভবত এটি যদি পূর্বনির্ধারিত আচরণ হয় তবে গ্রন্থাগারের লেখকদের পক্ষে আরও সহজ হবে, তবে আমি অনুমান করব যে কোনও লাইব্রেরিটি সঠিকভাবে লেখার জন্য এটি কিছুটা শক্ত করা আরও ভাল is
টুলমেকারস্টেভ

4
গ্রন্থাগারের লেখক কেন গ্রাহককে কোডল করতে হবে? যদি গ্রাহক অচল করতে চান তবে আমি কেন তাদের আটকাব?
কোয়ার্কলি

25

কনফিগারআউট (মিথ্যা) ব্যবহার করে আমি যে বৃহত্তম অঙ্কটি পেয়েছি তা হ'ল থ্রেড সংস্কৃতিটি সিস্টেম ডিফল্টে ফিরে আসে। আপনি যদি কোনও সংস্কৃতি কনফিগার করেছেন যেমন ...

<system.web>
    <globalization culture="en-AU" uiCulture="en-AU" />    
    ...

এবং আপনি এমন একটি সার্ভারে হোস্টিং করছেন যার সংস্কৃতিটি এন-ইউএসে সেট করা আছে, তারপরে আপনি কনফিগারআউট (মিথ্যা) নামক সংস্কৃতিআইএনফোর বলা হওয়ার আগে খুঁজে পাবেন urrent অর্থাত

// CultureInfo.CurrentCulture ~ {en-AU}
await xxxx.ConfigureAwait(false);
// CultureInfo.CurrentCulture ~ {en-US}

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


27
.NET এর আধুনিক সংস্করণগুলি (আমি মনে করি 4.6 সাল থেকে) থ্রেড জুড়ে সংস্কৃতি প্রচার করবে, এমনকি যদি ConfigureAwait(false)তা ব্যবহৃত হয়।
স্টিফেন ক্লিয়ারি

1
তথ্যের জন্য ধন্যবাদ। আমরা প্রকৃতপক্ষে .net 4.5.2
মিক

11

এর বাস্তবায়ন সম্পর্কে আমার কিছু সাধারণ ধারণা রয়েছে Task:

  1. টাস্ক নিষ্পত্তিযোগ্য তবুও আমাদের ব্যবহারের কথা নেইusing
  2. ConfigureAwait৪.৪-এ চালু হয়েছিল। Task4.0 সালে চালু হয়েছিল।
  3. .NET থ্রেডগুলি সর্বদা প্রাসঙ্গিক প্রবাহটি ব্যবহৃত হত (সিএলআর বইয়ের মাধ্যমে সি # দেখুন) তবে সেগুলি ডিফল্ট রূপায়ণে Task.ContinueWithখ / সি হয় না তা অনুধাবন করা হয়েছিল যে প্রসঙ্গের সুইচটি ব্যয়বহুল এবং এটি ডিফল্টরূপে বন্ধ করা আছে।
  4. সমস্যাটি হ'ল একটি গ্রন্থাগার বিকাশকারীকে তার ক্লায়েন্টদের প্রসঙ্গ প্রবাহ প্রয়োজন কিনা তা বিবেচনা করা উচিত নয় অতএব প্রসঙ্গে প্রবাহটি প্রবাহিত হবে কিনা তা সিদ্ধান্ত নেওয়া উচিত নয়।
  5. [পরে যুক্ত করা হয়েছে] কোনও প্রামাণ্য উত্তর এবং যথাযথ উল্লেখ নেই এবং আমরা এর সাথে লড়াই চালিয়ে যাচ্ছি যার অর্থ কেউ তাদের কাজ সঠিকভাবে করেন নি।

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

সমস্যাটি তখন হয় যখন একটি লাইব্রেরি একটি সিঙ্ক্রোনাস এপিআই প্রকাশ করে তবে অন্য একটি অ্যাসিনক্রোনাস এপিআই ব্যবহার করে - সুতরাং আপনাকে আপনার কোডটিতে Wait()/ ব্যবহার করতে হবে Result


6
1) আপনি চাইলে কল Task.Disposeকরতে পারেন; আপনার কেবল সময়ের বিশাল অংশের দরকার নেই। 2) Taskটিপিএলের অংশ হিসাবে। নেট 4.0 এ প্রবর্তিত হয়েছিল, যার প্রয়োজন নেই ConfigureAwait; যখন যুক্ত asyncকরা হয়েছিল, তারা Taskনতুন আবিষ্কারের পরিবর্তে বিদ্যমান প্রকারটি পুনরায় ব্যবহার করেছে Future
স্টিফেন ক্লিয়ারি

6
3) আপনি দুটি প্রকারের "প্রসঙ্গ" বিভ্রান্ত করছেন। সিএলআর এর মাধ্যমে সি # তে উল্লিখিত "প্রসঙ্গ" সর্বদা প্রবাহিত হয়, এমনকি Taskএস মধ্যেও ; "প্রসঙ্গ" দ্বারা নিয়ন্ত্রিত ContinueWithহয় একটি SynchronizationContextবা TaskScheduler। এই বিভিন্ন প্রসঙ্গে স্টিফেন টুবের ব্লগে বিশদভাবে ব্যাখ্যা করা হয়েছে
স্টিফেন ক্লিয়ারি

21
৪) গ্রন্থাগারের লেখককে তার কলকারীদের প্রসঙ্গে প্রবাহের প্রয়োজন কিনা তা যত্নের প্রয়োজন নেই কারণ প্রতিটি অ্যাসিনক্রোনাস পদ্ধতি স্বাধীনভাবে পুনরায় শুরু হয়। সুতরাং কলকারীদের যদি প্রসঙ্গ প্রবাহের প্রয়োজন হয় তবে গ্রন্থাগারের লেখক এটি প্রবাহিত করেছেন কি না তা নির্বিশেষে তারা এটিকে প্রবাহিত করতে পারে।
স্টিফেন ক্লিয়ারি

1
প্রথমদিকে, আপনি প্রশ্নের উত্তর না দিয়ে অভিযোগ করছেন বলে মনে হচ্ছে। এবং তারপরে আপনি "প্রসঙ্গটি" সম্পর্কে কথা বলছেন, নেট। এ বিভিন্ন ধরণের প্রসঙ্গ রয়েছে তা বাদে এবং আসলে কোনটি (বা কোন?) আপনি কথা বলছেন তা পরিষ্কার নয়। এমনকি যদি আপনি নিজেকে বিভ্রান্ত না করেন (তবে আমি মনে করি আপনিই রয়েছেন, আমি বিশ্বাস করি যে Threadএর সাথে প্রবাহিত কোন প্রসঙ্গ নেই তবে এর সাথে আর হয় না ContinueWith()), এটি আপনার উত্তরটি পড়তে বিভ্রান্ত করে তোলে।
সোভিক

1
পছন্দ করেছেন আমি ভেবেছিলাম আমি এটি পরিষ্কার করে দিয়েছি, তবে আমার ফ্রেসিংটি পরিষ্কার ছিল না।
অলিওস্টাড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.