সিঙ্ক্রোনাস কোডকে আসিঙ্ক্রোনাস কলে মোড়ানো


97

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

public OutputModel Calculate(InputModel input)
{
    // do some stuff
    return Service.LongRunningCall(input);
}

এবং পদ্ধতির ব্যবহার হ'ল (দ্রষ্টব্য, সেই পদ্ধতির কলটি একাধিকবার ঘটতে পারে):

private void MakeRequest()
{
    // a lot of other stuff: preparing requests, sending/processing other requests, etc.
    var myOutput = Calculate(myInput);
    // stuff again
}

এই পদ্ধতির একযোগে কাজ সরবরাহ করার জন্য আমি আমার পক্ষ থেকে বাস্তবায়নটি পরিবর্তন করার চেষ্টা করেছি এবং আমি এ পর্যন্ত এলাম।

public async Task<OutputModel> CalculateAsync(InputModel input)
{
    return await Task.Run(() =>
    {
        return Calculate(input);
    });
}

ব্যবহার ("অন্য জিনিসগুলি করুন" কোডের অংশটি পরিষেবাতে কল করার সাথে সাথে চলমান):

private async Task MakeRequest()
{
    // do some stuff
    var task = CalculateAsync(myInput);
    // do other stuff
    var myOutput = await task;
    // some more stuff
}

আমার প্রশ্নটি নিম্নলিখিত is আমি কি এএসপি.এনইটি অ্যাপ্লিকেশনটিতে কার্যকরকরণের গতি বাড়ানোর জন্য সঠিক পন্থাটি ব্যবহার করছি বা আমি সিঙ্ক্রোনাস কোডটি সংযোজিতভাবে চালানোর চেষ্টা করছি? দ্বিতীয় পদ্ধতিটি কেন এএসপি.নেটে বিকল্প নয় (যদি এটি সত্যই না হয়) তবে কী কেউ ব্যাখ্যা করতে পারেন? এছাড়াও, যদি এই ধরণের পদ্ধতির প্রয়োগ হয়, তবে কি এই মুহুর্তে আমাদের সম্পাদিত হতে পারে এমন একমাত্র কল যদি আমার এই পদ্ধতিটিকে অবিচ্ছিন্নভাবে কল করার দরকার হয় (আমার ক্ষেত্রে এমন ঘটনা ঘটে থাকে, যখন সমাপ্তির জন্য অপেক্ষা করার সময় অন্য কোনও জিনিস করার দরকার নেই)?
এই বিষয়ের নেটে বেশিরভাগ নিবন্ধগুলি async-awaitকোডটির সাথে অ্যাপ্রোচ ব্যবহার করে কভার করে , যা ইতিমধ্যে awaitableপদ্ধতি সরবরাহ করে, তবে এটি আমার ক্ষেত্রে নয়। এখানেএটি আমার ক্ষেত্রে বর্ণনা করার একটি সুন্দর নিবন্ধ, যা সমান্তরাল কলগুলির পরিস্থিতি বর্ণনা করে না, সিঙ্ক কলটি মোড়ানোর বিকল্পটি অস্বীকার করে, তবে আমার মতে আমার পরিস্থিতি হ'ল এটি করার উপলক্ষ।
সাহায্য এবং টিপস জন্য অগ্রিম ধন্যবাদ।

উত্তর:


119

দুটি ভিন্ন ধরণের সম্মতিতে পার্থক্য করা গুরুত্বপূর্ণ। অ্যাসিঙ্ক্রোনাস সমঝোতাটি যখন আপনার ফ্লাইটে একাধিক অ্যাসিনক্রোনাস অপারেশন থাকে (এবং যেহেতু প্রতিটি অপারেশন অ্যাসিঙ্ক্রোনাস, তাই তাদের মধ্যে কেউই আসলে একটি থ্রেড ব্যবহার করে না )। সমান্তরাল সম্মতি হ'ল যখন আপনার একাধিক থ্রেড থাকে প্রতিটি পৃথক অপারেশন করে।

প্রথমটি হ'ল এই অনুমানটি পুনরায় মূল্যায়ন করা:

পদ্ধতিটি নিজেই পরিষেবাতে সিঙ্ক্রোনাস কল এবং বাস্তবায়নটিকে ওভাররাইড করার কোনও সম্ভাবনা নেই।

যদি আপনার "পরিষেবা" কোনও ওয়েব পরিষেবা বা অন্য কোনও কিছু যা I / O- আবদ্ধ হয়, তবে এর জন্য একটি অ্যাসিনক্রোনাস এপিআই লিখাই ভাল সমাধান।

আমি এই ধারণাটি নিয়ে এগিয়ে যাব যে আপনার "পরিষেবা" একটি সিপিইউ-বাউন্ড অপারেশন যা অবশ্যই ওয়েব সার্ভারের মতো একই মেশিনে চালিত হবে।

যদি এটি হয় তবে মূল্যায়ন করার পরবর্তী জিনিসটি হ'ল আরেকটি অনুমান:

আমি দ্রুত কার্যকর করতে অনুরোধ প্রয়োজন।

আপনার যা করা দরকার তা কি আপনি সম্পূর্ণ নিশ্চিত? পরিবর্তে আপনি যে কোনও ফ্রন্ট-এন্ড পরিবর্তন করতে পারেন - যেমন, অনুরোধ শুরু করুন এবং প্রক্রিয়াজাতকরণের সময় ব্যবহারকারীকে অন্য কাজ করার অনুমতি দিন?

আমি এই ধারণাটি নিয়ে এগিয়ে যাব যে হ্যাঁ, আপনার ব্যক্তিগত অনুরোধটি দ্রুত কার্যকর করা দরকার।

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

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

সুতরাং, আপনি যদি এ পর্যন্ত পৌঁছে যান এবং আপনি অবশ্যই এএসপি.এনইটি-তে সমান্তরাল প্রক্রিয়াকরণ করতে চান তবে আপনার কাছে কয়েকটি বিকল্প রয়েছে।

অন্যতম সহজ পদ্ধতি হ'ল Task.Runআপনার বিদ্যমান কোডের সাথে খুব মিল similar যাইহোক, আমি কোনও CalculateAsyncপদ্ধতি প্রয়োগের প্রস্তাব দিচ্ছি না কারণ এটি বোঝায় যে প্রক্রিয়াটি অ্যাসিক্রোনাস (যা এটি নয়)। পরিবর্তে, Task.Runকলের বিন্দুতে ব্যবহার করুন:

private async Task MakeRequest()
{
  // do some stuff
  var task = Task.Run(() => Calculate(myInput));
  // do other stuff
  var myOutput = await task;
  // some more stuff
}

বিকল্পভাবে, যদি এটি আপনার কোডের সাথে ভালভাবে কাজ করে তবে আপনি Parallelপ্রকারটি, যেমন ,, বা Parallel.For, ব্যবহার করতে পারেন । কোডটির সুবিধা হ'ল অনুরোধের থ্রেডটি সমান্তরাল থ্রেডগুলির একটি হিসাবে ব্যবহৃত হয় এবং তারপরে থ্রেড প্রসঙ্গে (আবার উদাহরণের চেয়ে কম প্রসঙ্গের স্যুইচিং থাকে ) চালানো শুরু করে:Parallel.ForEachParallel.InvokeParallelasync

private void MakeRequest()
{
  Parallel.Invoke(() => Calculate(myInput1),
      () => Calculate(myInput2),
      () => Calculate(myInput3));
}

আমি একেবারেই এএসপি.এনইটি-তে সমান্তরাল লাইনকিউ (পিলিংকিউ) ব্যবহার করার পরামর্শ দিচ্ছি না।


4
বিস্তারিত উত্তরের জন্য অনেক ধন্যবাদ। আরও একটি বিষয় আমি পরিষ্কার করতে চাই। যখন আমি ব্যবহার করে সম্পাদন শুরু করি তখন Task.Runবিষয়বস্তুটি অন্য থ্রেডে চালিত হয় যা থ্রেড পুল থেকে নেওয়া হয়। তারপরে ব্লকিং কলগুলিকে (যেমন মাই কল থেকে সার্ভিসে) মোড়কের কোনও প্রয়োজন নেই Run, কারণ তারা সর্বদা প্রতিটি থ্রেড গ্রহণ করবে, যা পদ্ধতিটি কার্যকর করার সময় অবরুদ্ধ করা হবে। এই পরিস্থিতিতে async-awaitআমার ক্ষেত্রে কেবলমাত্র উপকারটিই বাকি রয়েছে তা একবারে বেশ কয়েকটি ক্রিয়া সম্পাদন করে। দয়া করে, আমি ভুল হলে আমাকে সংশোধন করুন।
ইডেল

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

4
পুনঃটুইট "..." এর অর্থ কী? এবং যেহেতু প্রতিটি অপারেশন অবিচ্ছিন্ন, তাই তাদের কেউই আসলে থ্রেড ব্যবহার করছে না ... "ধন্যবাদ!
alltej

4
@ অলতেজ: সত্যই অ্যাসিনক্রোনাস কোডের জন্য কোনও থ্রেড নেই
স্টিফেন ক্লিয়ারি

4
@ জোশুয়া ফ্র্যাঙ্ক: সরাসরি নয়। একটি সিঙ্ক্রোনাস এপিআই এর পিছনে কোড অবশ্যই সংজ্ঞা দ্বারা কলিং থ্রেড ব্লক করতে হবে। আপনি এগুলির একটি হিসাবে অ্যাসিক্রোনাস এপিআই ব্যবহার করতে পারেন BeginGetResponseএবং সেগুলির বেশ কয়েকটিতে শুরু করতে পারেন এবং তারপরে (একযোগে) ব্লকগুলি সমস্ত সম্পূর্ণ না হওয়া পর্যন্ত, তবে এই ধরণের পদ্ধতির কৌশলটি জটিল - দেখুন ব্লগ.স্টেফেনিলেচারি ডটকম / ২ / 07 / ডন্ট-ব্লক- অন -async-code.html এবং msdn.microsoft.com/en-us/magazine/mt238404.aspxasyncসম্ভব হলে সমস্ত দিক অবলম্বন করা সহজতর এবং ক্লিনার ।
স্টিফেন ক্লিয়ারি

1

আমি খুঁজে পেয়েছি যে নিম্নলিখিত কোডটি একটি কার্যকে সর্বদা অ্যাসিঙ্ক্রোনালি চালাতে রূপান্তর করতে পারে

private static async Task<T> ForceAsync<T>(Func<Task<T>> func)
{
    await Task.Yield();
    return await func();
}

এবং আমি এটি নিম্নলিখিত পদ্ধতিতে ব্যবহার করেছি

await ForceAsync(() => AsyncTaskWithNoAwaits())

এটি যেকোন টাস্ককে অবিচ্ছিন্নভাবে কার্যকর করবে যাতে আপনি এগুলিকে যখন, সমস্ত পরিস্থিতিতে এবং অন্যান্য ব্যবহারগুলিতে একত্রিত করতে পারেন।

আপনি আপনার ডাকা কোডের প্রথম লাইন হিসাবে কেবল টাস্ক.ইয়েল্ড () যোগ করতে পারেন।

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