সমান্তরালে একাধিক অ্যাসিঙ্ক পরিষেবাদি কল করা


17

আমার কয়েকটি অ্যাসিঙ্ক আরএসইটি পরিষেবা রয়েছে যা একে অপরের উপর নির্ভর করে না। এটি সার্ভিস 1 এর প্রতিক্রিয়ার "অপেক্ষা" করার সময়, আমি সার্ভিস 2, সার্ভিস 3 এবং আরও কল করতে পারি।

উদাহরণস্বরূপ, নীচে কোড দেখুন:

var service1Response = await HttpService1Async();
var service2Response = await HttpService2Async();

// Use service1Response and service2Response

এখন, এর service2Responseউপর নির্ভর করে না service1Responseএবং সেগুলি স্বাধীনভাবে আনা যায়। অতএব, দ্বিতীয় পরিষেবাটি কল করার জন্য আমার প্রথম পরিষেবাটির প্রতিক্রিয়াটির অপেক্ষার প্রয়োজন নেই।

আমি মনে করি না যে আমি Parallel.ForEachএখানে ব্যবহার করতে পারি কারণ এটি সিপিইউ বাউন্ড অপারেশন নয়।

এই দুটি অপারেশনকে সমান্তরালভাবে কল করার জন্য, আমি কী কল ব্যবহার করতে পারি Task.WhenAll? আমি যে সমস্যাটি ব্যবহার Task.WhenAllকরছি তা হ'ল এটি ফলাফল দেয় না। ফলাফল আনতে আমি কল করার task.Resultপরে কল করতে পারি Task.WhenAll, যেহেতু সমস্ত কাজ ইতিমধ্যে শেষ হয়ে গেছে এবং আমাদের আমাদের প্রতিক্রিয়া জানাতে হবে?

কোডের উদাহরণ:

var task1 = HttpService1Async();
var task2 = HttpService2Async();

await Task.WhenAll(task1, task2)

var result1 = task1.Result;
var result2 = task2.Result;

// Use result1 and result2

পারফরম্যান্সের ক্ষেত্রে এই কোডটি কি প্রথমটির চেয়ে ভাল? অন্য কোন পন্থা আমি ব্যবহার করতে পারি?


I do not think I can use Parallel.ForEach here since it is not CPU bound operation- আমি সেখানে যুক্তি দেখছি না। সংমেয় সম্মতি হয়।
রবার্ট হার্ভে

3
@ রবার্টহারভে আমি উদ্বেগ অনুমান করছি যে, এই প্রসঙ্গে, Parallel.ForEachনতুন থ্রেড তৈরি হবে যেখানে async awaitসমস্ত একক থ্রেডে করা হবে।
মেটাফাইট

@ কোডটি আপনার কোডটি ব্লক করার উপযুক্ত হলে এটি নির্ভর করে। উভয় প্রতিক্রিয়া প্রস্তুত না হওয়া পর্যন্ত আপনার দ্বিতীয় উদাহরণটি অবরুদ্ধ হবে। আপনার প্রথম উদাহরণটি সম্ভবতঃ কোডটি awaitপ্রস্তুত হওয়ার আগে প্রতিক্রিয়া ( ) ব্যবহার করার চেষ্টা করবে কেবল তখনই যুক্তিসঙ্গতভাবে ব্লক হয়ে যাবে ।
মেটাফাইট

আপনি যদি উভয় পরিষেবা প্রতিক্রিয়া গ্রহণের কোডটির কোনও বিমূর্ত উদাহরণ সরবরাহ করেন তবে আপনাকে আরও সন্তোষজনক উত্তর দেওয়া আরও সহজ হতে পারে।
মেটাফাইট

@ মেটাফাইট আমার দ্বিতীয় উদাহরণে আমি এই ধারণাটি নিয়ে কাজ WhenAllকরার আগে করছিলাম Resultযে এটি আগে সমস্ত কাজ শেষ করে es ফলাফল বলা হয়। যেহেতু, টাস্ক.সিসল্ট কলিং থ্রেডটিকে অবরুদ্ধ করেছে, আমি অনুমান করি যে আমি যদি কাজগুলি প্রকৃতপক্ষে সম্পন্ন হওয়ার পরে কল করি তবে তা তাত্ক্ষণিকভাবে ফলাফল ফিরে পাবে। আমি বুঝতে বৈধতা চাই।
অঙ্কিত বিজয়

উত্তর:


17

আমি টাস্কটি ব্যবহার করে দেখছি এমন একটি সমস্যা hen

কিন্তু এটা করে ফলাফল শূণ্য। এগুলি সমস্ত একটি সাধারণ ধরণের অ্যারেতে থাকবে, সুতরাং ফলাফলগুলি ব্যবহার করা সবসময় কার্যকর হয় না যে ফলস্বরূপ আপনি যে ফলাফলটি চান তার সাথে মিল রেখে অ্যারেতে আইটেমটি সন্ধান করতে Taskহবে এবং এটির জন্য এটি সম্ভবত ফেলে দিতে হবে প্রকৃত ধরণ, সুতরাং এই প্রসঙ্গে এটি সবচেয়ে সহজ / সর্বাধিক পঠনযোগ্য পদ্ধতি নাও হতে পারে তবে আপনি যখন প্রতিটি কাজ থেকে সমস্ত ফলাফল পেতে চান এবং সাধারণ ধরণটি সেই ধরণের যা আপনি তাদের সাথে আচরণ করতে চান তবে এটি দুর্দান্ত it's ।

ফলাফল আনতে আমি টাস্ককে কল করতে পারি Tas টাস্ককে ফোন করার পরে ফলাফল। কখন সমস্ত কাজ ইতিমধ্যে সম্পন্ন হয়েছে এবং আমার সমস্ত প্রতিক্রিয়া জানাতে হবে?

হ্যাঁ, আপনি এটি করতে পারে। আপনি এগুলিও করতে পারতেন await( awaitকোনও ত্রুটিযুক্ত কার্যে ব্যতিক্রমটি মোড়ানো Resultহবে , যেখানে সামগ্রিক ব্যতিক্রম ছুঁড়ে ফেলা হবে, তবে অন্যথায় এটি একই রকম হবে)।

পারফরম্যান্সের ক্ষেত্রে এই কোডটি কি প্রথমটির চেয়ে ভাল?

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

অন্য কোন পন্থা আমি ব্যবহার করতে পারি?

যদি এটি আপনার কাছে গুরুত্বপূর্ণ না যে আছে আপনি কি জানেন সব ব্যতিক্রম অপারেশন আপনি বরং শুধুমাত্র প্রথম এক তুলনায় সমান্তরাল করছেন সব মধ্যে নিক্ষিপ্ত, আপনি কেবল করতে পারেন awaitছাড়া কর্ম WhenAllসব সময়ে। কেবল প্রথম জিনিসটি WhenAllআপনাকে AggregateExceptionপ্রথম ত্রুটিযুক্ত কার্যটি আঘাত করার সময় নিক্ষেপ করার পরিবর্তে প্রতিটি ত্রুটিযুক্ত কাজ থেকে প্রতিটি একক ব্যতিক্রম যুক্ত করে। এটি এতটা সহজ:

var task1 = HttpService1Async();
var task2 = HttpService2Async();

var result1 = await task1;
var result2 = await task2;

এটি একই সাথে সমান্তরালে একা থাকাতে কাজগুলি চালাচ্ছে না। আপনি প্রতিটি টাস্ক ক্রমানুসারে সম্পন্ন হওয়ার জন্য অপেক্ষা করছেন। আপনি পারফরম্যান্ট কোড সম্পর্কে যত্ন না নিলে পুরোপুরি সূক্ষ্ম।
রিক ও'শিয়া

3
@ রিকো'সিয়া এটি ক্রিয়াকলাপ ক্রিয়াকলাপ শুরু করে। এটা করবে না দ্বিতীয় অপারেশন শুরু পরে এটি * শুরু হয় প্রথম অপারেশন। তবে অ্যাসিঙ্ক্রোনাস অপারেশন শুরু করা মূলত তাত্ক্ষণিক হওয়া উচিত (যদি এটি না হয় তবে এটি আসলে অ্যাসিনক্রোনাস নয়, এবং এটি সেই পদ্ধতিতে একটি বাগ)। একটি শুরু করার পরে এবং অন্যটি, প্রথম শেষ হওয়ার পরে এবং দ্বিতীয়টি শেষ না হওয়া পর্যন্ত এটি চলতে থাকবে না। যেহেতু দ্বিতীয়টি শুরু করার আগে কোনও কিছুই প্রথমটির সমাপ্তির জন্য অপেক্ষা করে না, তাই কিছুই তাদের একযোগে চালানো থেকে বিরত রাখছে না (যা তাদের সমান্তরালে চলমান সমান)।
21:54

@ সার্ভে আমি মনে করি এটি সত্য নয়। আমি দুটি অ্যাসিঙ্ক অপারেশনে লগিং যুক্ত করেছি যা প্রতিটি এক সেকেন্ডের কাছাকাছি সময় নিয়েছিল (উভয়ই এইচটিপি কল করে) এবং তারপরে আপনার পরামর্শ অনুসারে তাদের ডেকেছিল এবং নিশ্চিত যে পর্যাপ্ত টাস্ক 1 শুরু হয়েছে এবং শেষ হয়েছে এবং তারপরে টাস্ক 2 শুরু হয়ে শেষ হয়েছে।
ম্যাট ফ্রায়ার

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

@ সংজ্ঞা অনুসারে সার্ভে, অপেক্ষার অর্থ হ'ল পরবর্তী লাইনটি কার্যকর করার আগে অ্যাসিক্রোনাস টাস্ক শেষ না হওয়া পর্যন্ত আপনি অপেক্ষা করবেন। তাই না?
ম্যাট ফ্রিয়ার

0

এখানে এক্সটেনশন পদ্ধতি যা সেমফোরস্লিম ব্যবহার করে এবং সর্বাধিক ডিগ্রি সমান্তরালতা সেট করতে দেয়

    /// <summary>
    /// Concurrently Executes async actions for each item of <see cref="IEnumerable<typeparamref name="T"/>
    /// </summary>
    /// <typeparam name="T">Type of IEnumerable</typeparam>
    /// <param name="enumerable">instance of <see cref="IEnumerable<typeparamref name="T"/>"/></param>
    /// <param name="action">an async <see cref="Action" /> to execute</param>
    /// <param name="maxDegreeOfParallelism">Optional, An integer that represents the maximum degree of parallelism,
    /// Must be grater than 0</param>
    /// <returns>A Task representing an async operation</returns>
    /// <exception cref="ArgumentOutOfRangeException">If the maxActionsToRunInParallel is less than 1</exception>
    public static async Task ForEachAsyncConcurrent<T>(
        this IEnumerable<T> enumerable,
        Func<T, Task> action,
        int? maxDegreeOfParallelism = null)
    {
        if (maxDegreeOfParallelism.HasValue)
        {
            using (var semaphoreSlim = new SemaphoreSlim(
                maxDegreeOfParallelism.Value, maxDegreeOfParallelism.Value))
            {
                var tasksWithThrottler = new List<Task>();

                foreach (var item in enumerable)
                {
                    // Increment the number of currently running tasks and wait if they are more than limit.
                    await semaphoreSlim.WaitAsync();

                    tasksWithThrottler.Add(Task.Run(async () =>
                    {
                        await action(item).ContinueWith(res =>
                        {
                            // action is completed, so decrement the number of currently running tasks
                            semaphoreSlim.Release();
                        });
                    }));
                }

                // Wait for all tasks to complete.
                await Task.WhenAll(tasksWithThrottler.ToArray());
            }
        }
        else
        {
            await Task.WhenAll(enumerable.Select(item => action(item)));
        }
    }

নমুনা ব্যবহার:

await enumerable.ForEachAsyncConcurrent(
    async item =>
    {
        await SomeAsyncMethod(item);
    },
    5);

-2

আপনি হয় ব্যবহার করতে পারেন

Parallel.Invoke(() =>
{
    HttpService1Async();
},
() =>
{   
    HttpService2Async();
});

অথবা

Task task1 = Task.Run(() => HttpService1Async());
Task task2 = Task.Run(() => HttpService2Async());

//If you wish, you can wait for a particular task to return here like this:
task1.Wait();

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