সংশ্লেষে লিনকিউ ব্যবহার করে কীভাবে কাজের তালিকার জন্য অপেক্ষা করবেন?


88

আমার কাছে তৈরি করা কার্যগুলির একটি তালিকা রয়েছে:

public async Task<IList<Foo>> GetFoosAndDoSomethingAsync()
{
    var foos = await GetFoosAsync();

    var tasks = foos.Select(async foo => await DoSomethingAsync(foo)).ToList();

    ...
}

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

এটি উপরের ...ব্লকে কাজ করে:

var list = new List<Foo>();
foreach (var task in tasks)
    list.Add(await task);
return list;

এটি আমি যা চাই তা করে তবে এটি আনাড়ি বলে মনে হয়। আমি বরং এর চেয়ে সহজ কিছু লিখতে চাই:

return tasks.Select(async task => await task).ToList();

... তবে এটি সংকলন করে না আমি কী মিস করছি? বা এইভাবে জিনিসগুলি প্রকাশ করা কি সম্ভব নয়?


আপনার কি DoSomethingAsync(foo)প্রতিটি foo এর জন্য ক্রমিক ক্রিয়াকলাপ করা দরকার , বা এটি সমান্তরাল প্রার্থী For ফরচ প্রতিটি <ফু> ?
mdisibio

4
@ এমডিসিবিও - Parallel.ForEachব্লক করছে is এখানে নিদর্শনটি প্লেনসাইটের জোন স্কিটের অ্যাসিঙ্ক্রোনাস সি # ভিডিও থেকে এসেছে । এটি ব্লক না করে সমান্তরালে চালায়।
ম্যাট জনসন-পিন্ট

@ এমডিসিবিও - না তারা সমান্তরালে চালায়। এটি ব্যবহার করে দেখুন । (অতিরিক্তভাবে, দেখে মনে হচ্ছে যে আমি .ToList()কেবল ব্যবহার করতে চাইছি তবে আমার প্রয়োজন হবে না WhenAll))
ম্যাট জনসন-পিন্ট

পয়েন্ট নেওয়া হয়েছে। কীভাবে DoSomethingAsyncলেখা হয়েছে তার উপর নির্ভর করে তালিকাগুলি সমান্তরালে কার্যকর হতে পারে বা নাও হতে পারে। আমি একটি পরীক্ষা পদ্ধতি যা ছিল এবং এটি ছিল না এমন একটি সংস্করণ লিখতে সক্ষম হয়েছি, তবে উভয় ক্ষেত্রেই আচরণটি পদ্ধতি দ্বারা নির্ধারিত হয়, প্রতিনিধিটি কাজটি তৈরি করে না। মিশ্রণ জন্য দুঃখিত. তবে, যদি DoSomethingAsycফিরে আসে Task<Foo>, তবে awaitপ্রতিনিধিটির মধ্যে থাকা একেবারেই প্রয়োজনীয় নয় ... আমি মনে করি এটিই মূল বিষয় যা করার চেষ্টা করছিলাম।
mdisibio

উত্তর:


138

লিনকিউ asyncকোড সহ পুরোপুরি কাজ করে না , তবে আপনি এটি করতে পারেন:

var tasks = foos.Select(DoSomethingAsync).ToList();
await Task.WhenAll(tasks);

যদি আপনার কাজগুলি সমস্ত একই ধরণের মান ফেরত দেয় তবে আপনি এটি করতে পারেন:

var results = await Task.WhenAll(tasks);

যা বেশ সুন্দর। WhenAllএকটি অ্যারে ফেরত দেয়, তাই আমি বিশ্বাস করি যে আপনার পদ্ধতিটি ফলাফলগুলি সরাসরি ফিরিয়ে দিতে পারে:

return await Task.WhenAll(tasks);

11
কেবল এটি চিহ্নিত করতে চেয়েছিলেন যে var tasks = foos.Select(foo => DoSomethingAsync(foo)).ToList();
এটির

4
বা এমনকিvar tasks = foos.Select(DoSomethingAsync).ToList();
টড মেনিয়ার

4
এর পিছনে কারণ কী যে লিনক অসম্পূর্ণ কোডের সাথে পুরোপুরি কাজ করে না?
এহসান সাজ্জাদ ২

4
@ এহসান সাজ্জাদ: কারণ লিনকু টু অবজেক্টস সিঙ্ক্রয়ে ইন মেমরি অবজেক্টে কাজ করে। কিছু সীমাবদ্ধ জিনিস যেমন কাজ করে Select। তবে বেশিরভাগের মতো নয় Where
স্টিফেন ক্লিয়ারি

4
@ এহসান সাজ্জাদ: যদি অপারেশনটি I / O- ভিত্তিক হয় তবে আপনি asyncথ্রেড হ্রাস করতে ব্যবহার করতে পারেন ; যদি এটি সিপিইউযুক্ত এবং ইতিমধ্যে একটি পটভূমির থ্রেডে থাকে, তবে asyncকোনও সুবিধা সরবরাহ করবে না।
স্টিফেন ক্লিয়ারি

9

স্টিফেনের উত্তরের সম্প্রসারণের জন্য, আমি লিনকুতে সাবলীল শৈলী ধরে রাখতে নিম্নলিখিত এক্সটেনশন পদ্ধতিটি তৈরি করেছি । আপনি তারপর করতে পারেন

await someTasks.WhenAll()

namespace System.Linq
{
    public static class IEnumerableExtensions
    {
        public static Task<T[]> WhenAll<T>(this IEnumerable<Task<T>> source)
        {
            return Task.WhenAll(source);
        }
    }
}

10
ব্যক্তিগতভাবে, আমি আপনার এক্সটেনশন পদ্ধতির নাম দেবToArrayAsync
টর্ভিন

4

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

var events = Enumerable.Range(0, totalCount/ batchSize)
   .Select(x => x*batchSize)
   .Select(x => dbRepository.GetEventsBatch(x, batchSize).GetAwaiter().GetResult())
   .SelectMany(x => x);
foreach (var carEvent in events)
{
}

দ্রষ্টব্য .গেটওয়েটার () Get ব্যাচের আকারের ইভেন্টগুলি প্রক্রিয়া করা হলেই ডিবি অলসভাবে আঘাত হানবে।


1

ব্যবহার করুন Task.WaitAllবা Task.WhenAllযাহা হউক অপ্রাপ্ত।


4
এটিও কাজ করে না। Task.WaitAllঅবরুদ্ধ করা, প্রত্যাশিত নয় এবং এর সাথে কাজ করবে না Task<T>
ম্যাট জনসন-পিন্ট

@ ম্যাট জনসন WhenAll?
এলবি

হ্যাঁ এটাই! আমি বোবা বোধ করছি। ধন্যবাদ!
ম্যাট জনসন-পিন্ট

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