একাধিক async টাস্ক চালানো এবং সেগুলি সম্পূর্ণ হওয়ার অপেক্ষায়


265

কনসোল অ্যাপ্লিকেশনটিতে আমার একাধিক async কাজ চালানো উচিত এবং আরও প্রক্রিয়া করার আগে সেগুলি শেষ হওয়ার জন্য অপেক্ষা করুন।

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

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

এর মতো দৃশ্যের সহজ বাস্তবায়ন কী?

উত্তর:


440

উভয় উত্তর অপেক্ষারত Task.WhenAll:

var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();

await Task.WhenAll(task1, task2);

Task.WaitAllএবং এর মধ্যে প্রধান পার্থক্য Task.WhenAllহ'ল প্রাক্তনটি ( Waitএকক টাস্ক ব্যবহারের অনুরূপ) অবরুদ্ধ হয়ে যাবে, তবে পরবর্তীকালে সমস্ত কাজ শেষ না হওয়া অবধি কলারের কাছে নিয়ন্ত্রণ জোগানো হবে না এবং অপেক্ষা করা যাবে না।

আরও তাই, ব্যতিক্রম হ্যান্ডলিং পৃথক:

Task.WaitAll:

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

Task.WhenAll:

সরবরাহকৃত কোনও কাজ যদি একটি ত্রুটিযুক্ত অবস্থায় সম্পূর্ণ হয় তবে প্রত্যাবর্তিত টাস্কটি একটি ত্রুটিযুক্ত অবস্থায়ও পূর্ণ হবে, যেখানে এর ব্যতিক্রমগুলিতে সরবরাহিত প্রতিটি কাজ থেকে আন-র্যাপযুক্ত ব্যতিক্রমগুলির সংস্থার সংমিশ্রণ থাকবে।

যদি সরবরাহিত কোনও কাজই ত্রুটিযুক্ত না হয় তবে তাদের মধ্যে কমপক্ষে একটি বাতিল করা হয় তবে প্রত্যাবর্তিত কার্যটি বাতিল হওয়া অবস্থায় শেষ হবে।

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


4
আমি যখন এই চেষ্টা করি আমার কাজগুলি ক্রমান্বয়ে চালিত হয়? একেকজনের আগে প্রতিটি কাজ আলাদা করে শুরু করতে হবে await Task.WhenAll(task1, task2);?
Zapnologica

4
@ Zapnologica Task.WhenAllআপনার জন্য কাজগুলি শুরু করে না। আপনাকে সেগুলি "গরম" সরবরাহ করতে হবে, অর্থ ইতিমধ্যে শুরু হয়েছে।
যুবাল Itzchakov

2
ঠিক আছে. এটা বোধগম্য. তাহলে আপনার উদাহরণটি কী করবে? কারণ আপনি তাদের শুরু করেন নি?
Zapnologica

2
@ ইউয়ালআইটজচকভ আপনাকে অনেক ধন্যবাদ! এটি এত সহজ তবে এটি আজ আমাকে অনেক সাহায্য করেছে! কমপক্ষে
+1000

1
@ পিয়ার আমি অনুসরণ করছি না StartNewএগুলি সবকটির জন্য অপরিবর্তনীয়ভাবে অপেক্ষা করার সাথে নতুন কাজগুলিকে কীভাবে স্পিনিং করতে হবে?
ইয়ুভাল ইতজককভ

106

আপনি অনেকগুলি কাজ তৈরি করতে পারেন যেমন:

List<Task> TaskList = new List<Task>();
foreach(...)
{
   var LastTask = new Task(SomeFunction);
   LastTask.Start();
   TaskList.Add(LastTask);
}

Task.WaitAll(TaskList.ToArray());

48
আমি যখন সমস্ত প্রস্তাব করব
রবি

.স্টার্ট () এর পরিবর্তে অপেক্ষা করা কীওয়ার্ডটি ব্যবহার করে একই সাথে একাধিক নতুন থ্রেড শুরু করা সম্ভব?
ম্যাট ডব্লু

1
@ ম্যাটডাব্লু নং, আপনি যখন অপেক্ষা করবেন তখন এটি সম্পূর্ণ হওয়ার জন্য অপেক্ষা করবে। এই ক্ষেত্রে আপনি একটি বহু-থ্রেড পরিবেশ তৈরি করতে সক্ষম হবেন না। এই কারণেই সমস্ত কার্য লুপের শেষে অপেক্ষা করা হয়।
ভাইরাস

5
ভবিষ্যতের পাঠকদের জন্য ডাউনভোট করুন যেহেতু এটি পরিষ্কার করা হয়নি যে এটি একটি ব্লকিং কল।
জেআরউঘান

কেন এটি না করার কারণে গ্রহণযোগ্য উত্তর দেখুন।
EL MOJO

26

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

public static Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> action) {
    return Task.WhenAll(sequence.Select(action));
}

এটিকে কল করুন:

await sequence.ForEachAsync(item => item.SomethingAsync(blah));

বা একটি অ্যাসিঙ্ক ল্যাম্বদা সহ:

await sequence.ForEachAsync(async item => {
    var more = await GetMoreAsync(item);
    await more.FrobbleAsync();
});

26

আপনি WhenAllকোনটি প্রত্যাশিত প্রত্যাবর্তন করবেন Taskবা WaitAllযার কোনও রিটার্নের ধরণ নেই তা ব্যবহার করতে পারেন এবং Thread.Sleepসমস্ত কার্য সমাপ্ত, বাতিল বা ত্রুটিযুক্ত না হওয়া পর্যন্ত পরবর্তী কোড এক্সিকিউশন একযোগে অবরুদ্ধ করে দেবেন ।

এখানে চিত্র বর্ণনা লিখুন

উদাহরণ

var tasks = new Task[] {
    TaskOperationOne(),
    TaskOperationTwo()
};

Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);

যদি আপনি একটি যথাযথ ক্রমে কাজগুলি পরিচালনা করতে চান তবে আপনি এই আনসারটি থেকে অনুপ্রেরণা পেতে পারেন ।


দেরিতে পার্টিতে আসার জন্য দুঃখিত তবে, awaitপ্রতিটি ক্রিয়াকলাপের জন্য এবং একই সাথে আপনার ব্যবহার কেন WaitAllবা WhenAllTask[]আরম্ভের কাজগুলি ছাড়া হওয়া উচিত নয় await?
ডি জে জি

@dee zg আপনি ঠিক বলেছেন উপরের অপেক্ষার উদ্দেশ্যটি পরাস্ত করে। আমি আমার উত্তর পরিবর্তন করব এবং সেগুলি সরিয়ে দেব।
NtFreX

হ্যাঁ, এটা। বিবৃতির জন্য ধন্যবাদ! (সুন্দর উত্তরের জন্য উত্সাহিত করুন)
ডি জে

8

আপনি কী শৃঙ্খলাবদ্ধ করতে চান Task, না তাদের একটি সমান্তরাল পদ্ধতিতে ডাকা যেতে পারে?

শৃঙ্খলার জন্য
যেমন কিছু করতে

Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);

এবং Taskপ্রতিটি ক্ষেত্রে পূর্ববর্তী উদাহরণটি পরীক্ষা করতে ভুলবেন না ContinueWithকারণ এটির ফল্ট হতে পারে।

সমান্তরাল পদ্ধতিতে
আমি সবচেয়ে সহজ পদ্ধতিটি দেখতে পেলাম: Parallel.Invoke অন্যথায় এখানে Task.WaitAllবা আপনি WaitHandleশূন্য ক্রিয়াগুলি গণনা করার জন্য ব্যবহার করতে পারেন (অপেক্ষা করুন, একটি নতুন শ্রেণি রয়েছে CountdownEvent:), বা ...


3
উত্তরটির প্রশংসা করুন, তবে আপনার পরামর্শগুলি আরও কিছুটা ব্যাখ্যা করা যেতে পারে।
ড্যানিয়েল মিন্নার

@drminnaar উদাহরণগুলি সহ এমএসডিএন-এর লিঙ্কগুলির পাশে আর কোন ব্যাখ্যা আপনার প্রয়োজন? এমনকি আপনি লিঙ্কগুলিতে ক্লিক করেননি, তাই না?
Andreas Niedermair

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

@ড্রিম্ননার এখানে কোন অপরাধ নেওয়া হয়নি, আমি কেবল কৌতূহলী :)
আন্দ্রে নায়দারমায়ার

5

এইভাবে আমি এটি অ্যারে ফানক <> দিয়ে করব :

var tasks = new Func<Task>[]
{
   () => myAsyncWork1(),
   () => myAsyncWork2(),
   () => myAsyncWork3()
};

await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async    
Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync

1
আপনি কেবল এটি টাস্ক অ্যারে হিসাবে রাখছেন না কেন?
তালহা তালিপ আর্কগেজ

1
আপনি যদি সতর্ক না হন তবে @ টালহা-টালিপ-আকগিজ আপনার কাজগুলি কার্যকর করার প্রত্যাশা করবেন না এমন সময় আপনার কার্য সম্পাদন করুন। এটি একটি ফানক প্রতিনিধি হিসাবে করা আপনার উদ্দেশ্যটি পরিষ্কার করে।
ডালসফ্ট

5

তবুও অন্য উত্তর ... তবে আমি সাধারণত নিজেকে একটি ক্ষেত্রে খুঁজে পাই, যখন আমার একসাথে ডেটা লোড করার প্রয়োজন হয় এবং এটিকে ভেরিয়েবলগুলিতে রাখা দরকার, যেমন:

var cats = new List<Cat>();
var dog = new Dog();

var loadDataTasks = new Task[]
{
    Task.Run(async () => cats = await LoadCatsAsync()),
    Task.Run(async () => dog = await LoadDogAsync())
};

try
{
    await Task.WhenAll(loadDataTasks);
}
catch (Exception ex)
{
    // handle exception
}

1
যদি LoadCatsAsync()এবং LoadDogAsync()কেবল ডাটাবেস কল হয় তবে তারা আইও-আবদ্ধ। Task.Run()সিপিইউ-বাউন্ড কাজের জন্য; এটি অতিরিক্ত অপ্রয়োজনীয় ওভারহেড যুক্ত করে যদি আপনি যা করছেন সবই ডাটাবেস সার্ভারের প্রতিক্রিয়ার জন্য অপেক্ষা করছে। ইউভালের গৃহীত উত্তর হ'ল আইও-বাউন্ড কাজের জন্য সঠিক উপায়।
স্টিফেন কেনেডি

@ স্টেফেন কেনেডি আপনি কি দয়া করে পরিষ্কার করতে পারেন কোন ধরণের ওভারহেড এবং এটি পারফরম্যান্সকে কতটা প্রভাবিত করতে পারে? ধন্যবাদ!
ইয়াহোর হ্রোমাদস্কিই

মন্তব্য বাক্সে সংক্ষেপে বলা বেশ কঠিন হবে :) পরিবর্তে আমি স্টিফেন ক্লিয়ারির নিবন্ধগুলি পড়ার পরামর্শ দিচ্ছি - তিনি এই জিনিসগুলির বিশেষজ্ঞ। এখানে শুরু করুন: blog.stephencleary.com/2013/10/…
স্টিফেন কেনেডি

-1

এই পরিস্থিতিতে কিছু পরিস্থিতিতে কীভাবে টাস্কটি ব্যবহার করতে হয় তা দেখানোর জন্য আমি কোডের একটি অংশ প্রস্তুত করেছি।

    // method to run tasks in a parallel 
    public async Task RunMultipleTaskParallel(Task[] tasks) {

        await Task.WhenAll(tasks);
    }
    // methode to run task one by one 
    public async Task RunMultipleTaskOneByOne(Task[] tasks)
    {
        for (int i = 0; i < tasks.Length - 1; i++)
            await tasks[i];
    }
    // method to run i task in parallel 
    public async Task RunMultipleTaskParallel(Task[] tasks, int i)
    {
        var countTask = tasks.Length;
        var remainTasks = 0;
        do
        {
            int toTake = (countTask < i) ? countTask : i;
            var limitedTasks = tasks.Skip(remainTasks)
                                    .Take(toTake);
            remainTasks += toTake;
            await RunMultipleTaskParallel(limitedTasks.ToArray());
        } while (remainTasks < countTask);
    }

1
টাস্কের ফলাফল কীভাবে পাবেন? উদাহরণস্বরূপ, একটি ডেটিয়েটেবলের মধ্যে "সারিগুলি" সমান্তরালভাবে N কার্যগুলি থেকে) মার্জ করার জন্য এবং এটিকে গ্রিডভিউ আসপ নেটকে বাঁধুন?
প্রিগান্টনকোজনিরো ক্যাব্রন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.