লিনক সিলেক্টে অ্যাসিঙ্ক অপেক্ষা করুন


180

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

var inputs = events.Select(async ev => await ProcessEventAsync(ev))
                   .Select(t => t.Result)
                   .Where(i => i != null)
                   .ToList();

তবে এটি আমার কাছে খুব অদ্ভুত বলে মনে হচ্ছে, সবার আগে asyncএবং awaitনির্বাচনের ক্ষেত্রে use স্টিফেন ক্লিয়ারির এই উত্তর অনুসারে আমার এগুলি ফেলে দেওয়া উচিত।

তারপরে দ্বিতীয়টি Selectফলাফলটি নির্বাচন করে। এর অর্থ কি এই নয় যে টাস্কটি একেবারে অ্যাসিঙ্ক নয় এবং এটি সিঙ্ক্রোনাসিকভাবে সম্পাদিত হয় (কোনও কিছুর জন্য এত প্রচেষ্টা) না, বা টাস্কটি সংযোজনীয়ভাবে সম্পাদন করা হবে এবং যখন কাজটির বাকী কাজটি শেষ করা হবে তখন?

আমি কি স্টিফেন ক্লিয়ারির অন্য উত্তর অনুসারে নিম্নলিখিত কোডগুলি লিখতে চাই :

var tasks = await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev)));
var inputs = tasks.Where(result => result != null).ToList();

এবং এটি কি পুরোপুরি একই রকম?

var inputs = (await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev))))
                                       .Where(result => result != null).ToList();

আমি এই প্রকল্পে কাজ করার সময় আমি প্রথম কোডের নমুনাটি পরিবর্তন করতে চাই তবে আমি অ্যাসিঙ্ক কোডটি পরিবর্তন করতে খুব আগ্রহী নই। হতে পারে আমি কেবল কোনও কিছুর জন্য উদ্বিগ্ন এবং সমস্ত 3 কোডের নমুনা ঠিক একই জিনিসটি করে?

প্রসেসিভেন্টসেন্যাসটি দেখতে এরকম দেখাচ্ছে:

async Task<InputResult> ProcessEventAsync(InputEvent ev) {...}

প্রসেসিভেন্টসিন্যাকের রিটার্ন টাইপ কী?
tede24

@ tede24 এটি একটি কাস্টম ক্লাস হওয়ার Task<InputResult>সাথে InputResult
আলেকজান্ডার ডার্ক

আপনার সংস্করণগুলি আমার মতে পড়া খুব সহজ। যাইহোক, আপনি Selectনিজের কাজের আগে ফলাফলগুলি ভুলে গেছেন Where
সর্বোচ্চ

এবং ইনপুট রেজাল্টের কোনও ফলাফল সম্পত্তি আছে?
tede24

@ টেড টু 24 ফলাফলটি আমার শ্রেণীর নয় কাজের কাজ। এবং @ ম্যাক্স অপেক্ষার বিষয়টি নিশ্চিত হওয়া উচিত যে আমি Resultটাস্কের সম্পত্তি অ্যাক্সেস না করেই ফলাফল পেয়েছি
আলেকজান্ডার ডার্ক

উত্তর:


185
var inputs = events.Select(async ev => await ProcessEventAsync(ev))
                   .Select(t => t.Result)
                   .Where(i => i != null)
                   .ToList();

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

কলটি Selectবৈধ। এই দুটি লাইন মূলত অভিন্ন:

events.Select(async ev => await ProcessEventAsync(ev))
events.Select(ev => ProcessEventAsync(ev))

(কীভাবে একটি সিঙ্ক্রোনাস ব্যতিক্রম এড়ানো হবে সে সম্পর্কে একটি সামান্য পার্থক্য রয়েছে ProcessEventAsync, তবে এই কোডের প্রসঙ্গে এটি মোটেও গুরুত্বপূর্ণ নয়))

তারপরে দ্বিতীয় নির্বাচন করুন যা ফলাফল নির্বাচন করে which এর মানে কি এই নয় যে টাস্কটি একেবারে অ্যাসিঙ্ক নয় এবং এটি সিঙ্ক্রোনাসিকভাবে সম্পাদিত হয়েছে (কোনও কিছুর জন্য এত প্রচেষ্টা) না, বা টাস্কটি সংশ্লেষিতভাবে সম্পাদন করা হবে এবং যখন কাজটির বাকী কাজটি শেষ করা হবে তখন?

এর অর্থ হল যে ক্যোয়ারীটি ব্লক করা হচ্ছে। সুতরাং এটি আসলে অ্যাসিক্রোনাস নয়।

এটি ভেঙে দেওয়া:

var inputs = events.Select(async ev => await ProcessEventAsync(ev))

প্রথমে প্রতিটি ইভেন্টের জন্য একটি অ্যাসিনক্রোনাস অপারেশন শুরু করবে। তারপরে এই লাইন:

                   .Select(t => t.Result)

এই অপারেশনগুলি একবারে একটি সম্পন্ন হওয়ার জন্য অপেক্ষা করবে (প্রথমে এটি প্রথম ইভেন্টের অপারেশনের জন্য অপেক্ষা করে, তারপরে পরবর্তী, তারপরে পরবর্তী, ইত্যাদি)।

এই ভাগে আমি পরোয়া করি না, কারণ এটি ব্লক এবং যে কোন ব্যতিক্রম মোড়ানো হবে AggregateException

এবং এটি কি পুরোপুরি একই রকম?

var tasks = await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev)));
var inputs = tasks.Where(result => result != null).ToList();

var inputs = (await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev))))
                                       .Where(result => result != null).ToList();

হ্যাঁ, এই দুটি উদাহরণ সমান। তারা উভয়ই সমস্ত অ্যাসিনক্রোনাস অপারেশন ( events.Select(...)) শুরু করে, তারপরে অ্যাসিঙ্ক্রোনালি সমস্ত ক্রিয়াকলাপটি কোনও ক্রমে ( await Task.WhenAll(...)) সম্পূর্ণ হওয়ার জন্য অপেক্ষা করে , তারপরে বাকী কাজ ( Where...) নিয়ে এগিয়ে যান ।

এই দুটি উদাহরণই মূল কোড থেকে আলাদা। মূল কোডটি ব্লক করা হচ্ছে এবং এর ব্যতিক্রমগুলিকে মোড়ানো করবে AggregateException


এটি পরিষ্কার করার জন্য চিয়ার্স! সুতরাং ব্যতিক্রম একটি গুটিয়ে রাখা পরিবর্তে AggregateExceptionআমি দ্বিতীয় কোডে একাধিক পৃথক ব্যতিক্রম পেতে পারি?
আলেকজান্ডার ডার্ক

1
@ আলেকজান্দার ডার্ক: না, পুরানো এবং নতুন কোড উভয় ক্ষেত্রেই কেবল প্রথম ব্যতিক্রম উত্থাপিত হবে। তবে Resultএটি দিয়ে গুটিয়ে রাখা হত AggregateException
স্টিফেন ক্লিয়ারি

আমি এই কোডটি ব্যবহার করে আমার এএসপি.নেট এমভিসি কন্ট্রোলারে একটি অচলাবস্থা পাচ্ছি। আমি এটি Task.Run (…) ব্যবহার করে সমাধান করেছি। আমার এটি সম্পর্কে ভাল অনুভূতি নেই। যাইহোক, এটি অসিঙ্ক xUnit পরীক্ষায় চলার ঠিক ঠিক পরে শেষ হয়েছে। কি হচ্ছে?
সুপারজেএমএন

2
@SuperJMN: প্রতিস্থাপন stuff.Select(x => x.Result);সঙ্গেawait Task.WhenAll(stuff)
স্টিফেন Cleary

1
@ ড্যানিয়েলস: এগুলি মূলত একই রকম। কিছু তফাত রয়েছে যেমন রাজ্য মেশিন, ক্যাপচারিং প্রসঙ্গ, সিঙ্ক্রোনাস ব্যতিক্রমগুলির আচরণ। Blog.stephencleary.com/2016/12/elider-async-await.html-
স্টিফেন ক্লিয়ারি

25

বিদ্যমান কোডটি কাজ করছে, তবে থ্রেডটি ব্লক করছে।

.Select(async ev => await ProcessEventAsync(ev))

প্রতিটি ইভেন্টের জন্য একটি নতুন টাস্ক তৈরি করে, তবে

.Select(t => t.Result)

প্রতিটি নতুন কাজ শেষ হওয়ার অপেক্ষায় থ্রেডটি ব্লক করে।

অন্যদিকে আপনার কোড একই ফলাফল উত্পাদন করে তবে অ্যাসিনক্রোনাস রাখে।

আপনার প্রথম কোডটিতে একটি মন্তব্য। এই লাইন

var tasks = await Task.WhenAll(events...

একটি একক টাস্ক তৈরি করবে যাতে ভেরিয়েবলের নাম একবচন রাখা উচিত।

অবশেষে আপনার শেষ কোডটি একই রকম হয় তবে এটি আরও সংযোগযুক্ত

রেফারেন্সের জন্য: Task.Wait / Task.WhenAll


সুতরাং প্রথম কোড ব্লক আসলে সিঙ্ক্রোনস কার্যকর করা হয়?
আলেকজান্ডার ডার্ক

1
হ্যাঁ, কারণ ফলাফলটিতে অ্যাক্সেস একটি অপেক্ষা তৈরি করে যা থ্রেডকে ব্লক করে। অন্যদিকে যখন একটি নতুন টাস্ক তৈরি করে আপনি অপেক্ষা করতে পারেন।
tede24

1
এই প্রশ্নে ফিরে আসা এবং tasksভেরিয়েবলের নাম সম্পর্কে আপনার মন্তব্যটি দেখে আপনি পুরোপুরি ঠিক বলেছেন। ভয়াবহ পছন্দ, এগুলি এখনই প্রতীক্ষিত হওয়ার কারণে তারা কার্যগুলিও নয়। আমি যেমন প্রশ্নটি ঠিক তেমনি রেখে দেব
আলেকজান্ডার ডার্ক

13

লিনকে উপলভ্য বর্তমান পদ্ধতিগুলির সাথে এটি দেখতে বেশ কুৎসিত দেখাচ্ছে:

var tasks = items.Select(
    async item => new
    {
        Item = item,
        IsValid = await IsValid(item)
    });
var tuples = await Task.WhenAll(tasks);
var validItems = tuples
    .Where(p => p.IsValid)
    .Select(p => p.Item)
    .ToList();

আশা করি .NET এর নিম্নলিখিত সংস্করণগুলি সংগ্রহের কাজগুলি এবং কার্যাদি পরিচালনা করার জন্য আরও মার্জিত টুলিংয়ের সাথে উপস্থিত হবে।


12

আমি এই কোডটি ব্যবহার করেছি:

public static async Task<IEnumerable<TResult>> SelectAsync<TSource,TResult>(this IEnumerable<TSource> source, Func<TSource, Task<TResult>> method)
{
      return await Task.WhenAll(source.Select(async s => await method(s)));
}

এটার মত:

var result = await sourceEnumerable.SelectAsync(async s=>await someFunction(s,other params));

5
এটি কেবল বিদ্যমান কার্যকারিতাটিকে আরও
অস্পষ্টভাবে ইমোতে আবৃত করে

বিকল্পটি হ'ল ফলাফলের ফলাফল = টাস্কের জন্য অপেক্ষা করুন henএখন সমস্ত (উত্সআণ্যযোগ্য S নির্বাচন করুন (async s => কিছু ফাংশন (গুলি, অন্যান্য প্যারাম) এর জন্য অপেক্ষা করুন)) এটি কাজ করে, তবে এটি লিনকিও নয়
সিডারাইট জ্যাকডেভেডেক্স

দ্বিতীয় বিট কোডে উল্লিখিত Func<TSource, Task<TResult>> methodথাকা উচিত নয় other params?
ম্যাট্রামোস

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

4
এটি একটি সুন্দর এক্সটেনশন পদ্ধতি। কেন এটি "আরও অস্পষ্ট" হিসাবে বিবেচিত হয়েছিল তা নিশ্চিত নয় - এটি সিনক্রোনাসের সাথে শব্দার্থগতভাবে উপমাযুক্ত Select(), তাই এটি একটি মার্জিত ড্রপ-ইনও।
nullPainter

10

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

public static async Task<IEnumerable<T>> WhenAll<T>(this IEnumerable<Task<T>> tasks)
{
    return await Task.WhenAll(tasks);
}

যাতে এটি পদ্ধতিতে শৃঙ্খলাবদ্ধকরণের সাথে ব্যবহারযোগ্য:

var inputs = await events
  .Select(async ev => await ProcessEventAsync(ev))
  .WhenAll()

1
Waitবাস্তবে অপেক্ষা না করা অবস্থায় আপনাকে পদ্ধতিটি কল করা উচিত নয় । এটি একটি টাস্ক তৈরি করছে যা সমস্ত কাজ সম্পূর্ণ হয়ে গেলে সম্পূর্ণ। এটিকে কল করুন WhenAll, Taskপদ্ধতিটি যেমন অনুকরণ করে like পদ্ধতিটি হওয়াও এটি অর্থহীন async। শুধু কল করুন WhenAllএবং এটি দিয়ে সম্পন্ন করুন।
পরিবেশন করুন

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

@ সার্ভি ফেয়ার পয়েন্ট, তবে আমি বিশেষ করে নামের কোনওটি পছন্দ করি না। যখন সমস্ত এটিকে একটি ইভেন্টের মতো মনে হয় যা এটি একেবারেই নয়।
ড্যারিল

3
@ আলেকজান্দার ডার্কের সুবিধা হ'ল আপনি এটিকে মেথড শেইনে ব্যবহার করতে পারেন।
ড্যারিল

1
@ ড্যারিল কারণ WhenAllএকটি মূল্যায়িত তালিকা ফেরত দেয় (এটি অলসভাবে মূল্যায়ন করা হয় না), এটি বোঝাতে রিটার্নের ধরণটি ব্যবহার করার জন্য একটি যুক্তি তৈরি করা যেতে পারে Task<T[]>। প্রতীক্ষিত হলে, এটি এখনও লিনক ব্যবহার করতে সক্ষম হবে, তবে এটি আলস্য নয় বলেও যোগাযোগ করে।
জেএডি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.