"ডুমোথিংসিংসিং () এর ফলনের প্রত্যাশার অপেক্ষা করা কি সম্ভব?"


108

নিয়মিত পুনরাবৃত্তকারী ব্লক (যেমন "ফলন ফেরত") কি "অ্যাসিঙ্ক" এবং "অপেক্ষা" এর সাথে বেমানান?

এটি আমি যা করার চেষ্টা করছি তার একটি ভাল ধারণা দেয়:

async Task<IEnumerable<Foo>> Method(String [] Strs)
{
    // I want to compose the single result to the final result, so I use the SelectMany
    var finalResult = UrlStrings.SelectMany(link =>   //i have an Urlstring Collection 
                   await UrlString.DownLoadHtmlAsync()  //download single result; DownLoadHtmlAsync method will Download the url's html code 
              );
     return finalResult;
}

তবে, "সংস্থান থেকে বার্তা স্ট্রিং লোড করতে না পারা" উদ্ধৃত করে একটি সংকলক ত্রুটি পেয়েছি।

এখানে আরও একটি প্রচেষ্টা:

async Task<IEnumerable<Foo>> Method(String [] Strs)
{
    foreach(var str in strs)
    {
        yield return await DoSomethingAsync( str)
    }
}

তবে আবার, সংকলকটি একটি ত্রুটি ফেরায়: "সংস্থান থেকে বার্তা স্ট্রিং লোড করতে অক্ষম"।


আমার প্রকল্পের আসল প্রোগ্রামিং কোডটি এখানে

এটি খুব কার্যকর যখন আমার একটি তালিকার কার্য থাকে, সেই কাজটি কোনও ইউআরএল থেকে এইচটিএমএল ডাউনলোড করা যায় এবং আমি "ফলন প্রত্যাবর্তনের প্রত্যাশিত টাস্ক" সিনট্যাক্সটি ব্যবহার করি, ফলাফলটি আমি চাই IEnumerable<Foo>। আমি এই কোডটি লিখতে চাই না:

async Task<IEnumerable<String>> DownLoadAllURL(String [] Strs)
{
    List<Foo> htmls= new ...
    foreach(var str in strs)
    {
        var html= await DownLoadHtmlAsync( str)
        htmls.Add(item)
    }
    return htmls;
}

তবে মনে হচ্ছে আমাকেও করতে হবে।

কোন সাহায্যের জন্য ধন্যবাদ।


4
এই প্রশ্নটি বিশেষভাবে পরিষ্কার নয়, আপনি ঠিক কী করতে চান এটি সম্পর্কে আপনাকে বিশদভাবে বর্ণনা করা উচিত - কেবলমাত্র একটি কোডের নমুনা থেকে আপনি কী করতে চান তা নির্ধারণ করা কঠিন its
জাস্টিন

3
Ix_Experimental-এসিঙ্ক NuGet প্যাকেজ "অ্যাসিঙ্ক্রোনাস তথ্যসংগ্রহকারী" LINQ সমর্থনে সম্পূর্ণ অন্তর্ভুক্ত করা হয়েছে। তারা IAsyncEnumerator<T>এর্ন দ্বারা নির্ধারিত ধরণটি ব্যবহার করে ।
স্টিফেন ক্লিয়ারি

@ স্টেফেনক্রিয়ারি যে প্যাকেজ তালিকাভুক্ত করা হয়েছে। যেহেতু এটি যুগ যুগ আগে & এমএস এর রেক্সটিয়াম দ্বারা রচিত, আপনি কি জানেন যে এটি আরএক্সে পরিণত হয়েছে কিনা?
জোব্রোকহাউস

@ জোব্রোকহাউস: দেখে মনে হচ্ছে এটি আইএক্স-অ্যাসিঙ্ক হিসাবে বেঁচে আছে
স্টিফেন ক্লিয়ারি

উত্তর:


72

আপনি যা বর্ণনা করছেন তা Task.WhenAllপদ্ধতিটি দিয়ে সম্পন্ন করা যায় । লক্ষ্য করুন কীভাবে কোডটি একটি সাধারণ ওলাইনারে পরিণত হয়। যা ঘটে তা হ'ল প্রতিটি পৃথক ইউআরএল ডাউনলোড শুরু হয় এবং তারপরে অপেক্ষা করা যায় WhenAllএমন এককগুলিতে সেই অপারেশনগুলিকে একত্রিত করে ব্যবহার করা হয় Task

Task<IEnumerable<string>> DownLoadAllUrls(string[] urls)
{
    return Task.WhenAll(from url in urls select DownloadHtmlAsync(url));
}

10
এক্ষেত্রে async / প্রতীক্ষার প্রয়োজন নেই। কেবল asyncপদ্ধতি থেকে সরান এবং return Task.WhenAllসরাসরি করুন।
লুস্কুবাল

22
শেষ লাইনটি আরও urls.Select(DownloadHtmlAsync)
সংক্ষেপে

1
এটি হ'ল আমি যে সমস্যার মুখোমুখি হচ্ছিলাম তা হ'ল (অলসভাবে ইউআরআইয়ের একটি সিরিজ থেকে স্ট্রিংগুলি ডাউনলোড করে)। ধন্যবাদ.
জেমস কো

13
এটি আসলে এই প্রশ্নের উত্তর দেয় না Is it possible to await yield? আপনি এই একটি ব্যবহারের ক্ষেত্রে সবেমাত্র একটি কাজ খুঁজে পেয়েছেন। সাধারণ প্রশ্নের উত্তর দেয়নি।
বুহ বুহ

1
আমি ফিরে আসার প্রবণতা হব কারণ এটি Task<string[]>ইঙ্গিত দেয় যে আপনি আর পিছনে প্রেরণা দিয়ে কোনও পুনরাবৃত্তি ফিরিয়ে দিচ্ছেন না। সমস্ত ইউআরএল ডাউনলোড করা হচ্ছে।
johnnycardy

73

tl; ডাঃ ইটারেটরগুলি ফলন হিসাবে প্রয়োগ করা একটি ব্লক করা নির্মাণ, তাই এখনই অপেক্ষা করুন এবং ফলনটি বেমানান।

দীর্ঘ কারণ একটি উপর পুনরাবৃত্তি IEnumerableএকটি ব্লকিং অপারেশন, চিহ্নিত হিসাবে চিহ্নিত একটি পদ্ধতি asyncএখনও এটি একটি ব্লকিং পদ্ধতিতে কার্যকর করা হবে, যেহেতু অপারেশনটি শেষ হওয়ার জন্য এটি অপেক্ষা করতে হবে।

async Task<IEnumerable<Foo>> Method(String [] Strs)
{
  foreach(var str in strs)
  {
    yield return await DoSomethingAsync( str)
  }
}  

অপেক্ষার Methodঅর্থ মিক্স করে। আপনি পর্যন্ত অপেক্ষা করতে চান Taskএকটি হয়েছে IEnumerableএবং তারপর উপর iterating এ অবরুদ্ধ? অথবা আপনি প্রতিটি মানের জন্য অপেক্ষা করার চেষ্টা করছেন IEnumerable?

আমি ধরে নিয়েছি দ্বিতীয়টি হ'ল কাঙ্ক্ষিত আচরণ এবং সে ক্ষেত্রে বিদ্যমান ইটারেটর শব্দার্থ কাজ করবে না। IEnumerator<T>ইন্টারফেস মূলত

public interface IEnumerator<T>
  T Current;
  bool MoveNext();
}

আমি এড়াচ্ছি Reset()যেহেতু এটি অ্যাসিক্রোনাস ফলাফলের ক্রমটির কোনও মানে করে না। তবে আপনার যা প্রয়োজন তা হ'ল এইরকম:

public interface IAsyncEnumerator<T>
  T Current;
  Task<bool> MoveNext();
}

অবশ্যই, foreachএটির সাথেও কাজ করবে না এবং আপনাকে ম্যানুয়ালি এইভাবে পুনরাবৃত্তি করতে হবে:

var moveNext = await asyncEnumerator.MoveNext();
while(moveNext) {

  // get the value that was fetche asynchronously
  var v = asyncEnumerator.Current;

  // do something with that value

  // suspend current execution context until next value arrives or we are done
  moveNext = await asyncEnumerator.MoveNext();
}

1
আপনি কি মনে করেন যে পরবর্তী সি # ভাষার সংস্করণটি foreachআপনার অনুমানের জন্য সমর্থন যোগ করবে IAsyncEnumerator<T>?
দাই

1
@ ডাই আমি পাইপলাইনে এটি খুব মনে করি। সি # 8.0 / এর জন্য পড়েছি।
নওফাল

@ ডাই, ডকস.মাইক্রোসফটকম / en- us/ dotnet/ csharp/ whats- new/
ভিক্টর ইয়ারেমা

40

সি # 8.0 ( লিঙ্ক # 1 এবং লিঙ্ক # 2 ) এ নতুন বৈশিষ্ট্য অনুসারে আমাদের IAsyncEnumerable<T>ইন্টারফেস সমর্থন থাকবে যা আপনার দ্বিতীয় প্রচেষ্টা বাস্তবায়নের অনুমতি দেবে। এটি দেখতে এটির মতো হবে:

async Task<Foo> DoSomethingAsync(string url)
{
    ...
}       
// producing IAsyncEnumerable<T>
async IAsyncEnumerable<Foo> DownLoadAllURL(string[] strs)
{
    foreach (string url in strs)
    {
        yield return await DoSomethingAsync(url);
    }
}
...
// using
await foreach (Foo foo in DownLoadAllURL(new string[] { "url1", "url2" }))
{
    Use(foo);
}

আমরা সি # 5 তে একই আচরণ অর্জন করতে পারি তবে ভিন্ন শব্দার্থতত্ত্বের সাথে:

async Task<Foo> DoSomethingAsync(string url)
{
    ...
}
IEnumerable<Task<Foo>> DownLoadAllURL(string[] strs)
{
    foreach (string url in strs)
    {
        yield return DoSomethingAsync(url);
    }
}

// using
foreach (Task<Foo> task in DownLoadAllURL(new string[] { "url1", "url2" }))
{
    Foo foo = await task;
    Use(foo);
}

ব্রায়ান গিদিনের উত্তর থেকে বোঝা যায় যে কলিং কোডটি সমান্তরালভাবে প্রাপ্ত ফলাফলগুলির সংকলনটি অবিচ্ছিন্নভাবে পাবেন। উপরের কোডটি বোঝায় যে কলিং কোডটি অবিচ্ছিন্ন উপায়ে একের পর এক স্ট্রিমের মতো ফলাফল পাবে।


17

আমি জানি যে উত্তরটি নিয়ে আমি অনেক দেরি করেছি, তবে এই লাইব্রেরির সাহায্যে এখানে আরও একটি সহজ সমাধান অর্জন করা যেতে পারে
: গিটহব: https://github.com/tyrotoxin/AsyncEnumerable
NuGet.org: https: //www.nuget .org / প্যাকেজ / AsyncEnumerator /
এটি আরএক্স থেকে অনেক সহজ ler

using System.Collections.Async;

static IAsyncEnumerable<string> ProduceItems(string[] urls)
{
  return new AsyncEnumerable<string>(async yield => {
    foreach (var url in urls) {
      var html = await UrlString.DownLoadHtmlAsync(url);
      await yield.ReturnAsync(html);
    }
  });
}

static async Task ConsumeItemsAsync(string[] urls)
{
  await ProduceItems(urls).ForEachAsync(async html => {
    await Console.Out.WriteLineAsync(html);
  });
}

5

এই বৈশিষ্ট্যটি সি # 8.0 হিসাবে উপলব্ধ হবে। https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/

এমএসডিএন থেকে

অ্যাসিঙ্ক স্ট্রিম

সি # 5.0 এর অ্যাসিঙ্ক / অপেক্ষার বৈশিষ্ট্যটি আপনাকে কলব্যাক ছাড়াই সোজা কোডে অ্যাসিনক্রোনাস ফলাফল (এবং উত্পাদন) করতে দেয়:

async Task<int> GetBigResultAsync()
{
    var result = await GetResultAsync();
    if (result > 20) return result; 
    else return -1;
}

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

আমরা আইএএনসিএনইউনামেবলের সাথে পরিচয় করিয়ে দিই যা আপনি প্রত্যাশা করতেন ঠিক তেমনই; আইইনুমারেবলের একটি অ্যাসিঙ্ক্রোনাস সংস্করণ। ভাষা আপনাকে তাদের উপাদানগুলি গ্রাস করার জন্য তাদের উপর ভবিষ্যদ্বাণী করার অপেক্ষায় থাকতে পারে এবং উপাদান তৈরি করতে তাদের কাছে ফিরে আসে।

async IAsyncEnumerable<int> GetBigResultsAsync()
{
    await foreach (var result in GetResultsAsync())
    {
        if (result > 20) yield return result; 
    }
}


1

প্রথমত, মনে রাখবেন যে অ্যাসিঙ্ক স্টাফ শেষ হয়নি। সি # 5 প্রকাশের আগে সি # টিমের এখনও অনেক দীর্ঘ পথ যেতে হবে

বলা হচ্ছে, আমি মনে করি আপনি হয়ত এই কাজগুলিকে অন্যরকমভাবে DownloadAllHtmlফাংশন থেকে সরিয়ে নিতে চাইবেন ।

উদাহরণস্বরূপ, আপনি এর মতো কিছু ব্যবহার করতে পারেন:

IEnumerable<Task<string>> DownloadAllUrl(string[] urls)
{
    foreach(var url in urls)
    {
        yield return DownloadHtmlAsync(url);
    }
}

async Task<string> DownloadHtmlAsync(url)
{
    // Do your downloading here...
}

এমন নয় যে DownloadAllUrlফাংশন নয় একটি ASYNC কল। তবে, আপনি অ্যাসিঙ্ক কলটি অন্য কোনও কার্য (যেমন DownloadHtmlAsync) এ প্রয়োগ করতে পারেন ।

টাস্ক সমান্তরাল গ্রন্থাগারের কাজ .ContinueWhenAnyএবং .ContinueWhenAllকার্য রয়েছে।

এটি এভাবে ব্যবহার করা যেতে পারে:

var tasks = DownloadAllUrl(...);
var tasksArray = tasks.ToArray();
var continuation = Task.Factory.ContinueWhenAll(tasksArray, completedTasks =>
{
    completedtask
});
continuation.RunSynchronously();

আপনি যদি আপনার পদ্ধতিটিকে async হিসাবে সংজ্ঞায়িত করেন তবে আপনার একটি 'শিরোনাম' (লুপের আগে )ও থাকতে পারে Task<IEnumerable<Task<string>>> DownloadAllUrl। অথবা, যদি আপনি 'পাদলেখ' ক্রিয়া চান IEnumerable<Task>। যেমন gist.github.com/1184435
জনাথন ডিকিনসন

1
এখন যে asyncকাপড় হয় সমাপ্ত এবং C # 5.0 হয় মুক্তি, এই করতে আপডেট করা।
CasperOne

আমি এটি পছন্দ করি, তবে কীভাবে এই ক্ষেত্রে ভবিষ্যদ্বাণী করা (get url এর অপেক্ষা করা url ()) {ফলন ফেরত getContent (url)}; আমি কেবল দুটি পদ্ধতিতে বিভক্ত হওয়ার উপায় খুঁজে পেয়েছি।
হুয়ান পাবলো গার্সিয়া কোয়েলো


-1

এই সমাধানটি প্রত্যাশার মতো কাজ করে। await Task.Run(() => enumerator.MoveNext())অংশ নোট করুন ।

using (var enumerator = myEnumerable.GetEnumerator())
{
    while (true)
    {
        if (enumerator.Current != null)
        {
            //TODO: do something with enumerator.Current
        }

        var enumeratorClone = monitorsEnumerator;
        var hasNext = await Task.Run(() => enumeratorClone.MoveNext());
        if (!hasNext)
        {
            break;
        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.