¿Es posible “esperar rendimiento rendimiento DoSomethingAsync ()”

¿Los bloques de iterador regulares (es decir, “retorno de rendimiento”) son incompatibles con “asincrónico” y “aguardar”?

Esto da una buena idea de lo que estoy tratando de hacer:

async Task<IEnumerable> 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; } 

Sin embargo, aparece un error del comstackdor que dice “no se puede cargar cadena de mensaje de los recursos”.

Aquí hay otro bash:

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

Pero, de nuevo, el comstackdor devuelve un error: “no se puede cargar cadena de mensajes de los recursos”.


Aquí está el código de progtwigción real en mi proyecto

Esto es muy útil cuando tengo una Tarea de lista, esa tarea se puede descargar HTML desde una URL y utilizo la syntax “devolver rendimiento aguardan tarea”, el resultado es que quiero IEnumerable . No quiero escribir este código:

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

Pero parece que tengo que hacerlo.

Gracias por cualquier ayuda.

Lo que está describiendo se puede lograr con la Task.WhenAll . Task.WhenAll se Task.WhenAll método. Observe cómo el código se convierte en un simple trazador de líneas. Lo que sucede es que cada url individual comienza a descargarse y luego, WhenAll se usa todo, se combinan esas operaciones en una única Task que puede esperarse.

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

tl; dr Iteradores tal como se implementa con el rendimiento son una construcción de locking, por lo que en este momento esperan y el rendimiento son incompatibles.

Long Debido a que iterar sobre un IEnumerable es una operación de locking, llamar a un método marcado como async todavía lo ejecutará de forma bloqueante, ya que tiene que esperar a que termine esa operación.

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

El Method espera mezcla significados. ¿Desea esperar hasta que la Task tenga un IEnumerable y luego bloquear al iterar sobre él? ¿O estás tratando de esperar cada valor del IEnumerable ?

Supongo que el segundo es el comportamiento deseado y en ese caso la semántica Iterator existente no funcionará. La IEnumerator es básicamente

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

Estoy ignorando Reset() ya que no tiene sentido para una secuencia de resultados asincrónicos. Pero lo que necesitarías es algo como esto:

 public interface IAsyncEnumerator T Current; Task MoveNext(); } 

Por supuesto, foreach tampoco funcionará con esto y tendrías que iterar manualmente así:

 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(); } 

Sé que ya llegué tarde con la respuesta, pero aquí hay otra solución simple que se puede lograr con esta biblioteca:
GitHub: https://github.com/tyrotoxin/AsyncEnumerable
NuGet.org: https://www.nuget.org/packages/AsyncEnumerator/
Es mucho más simple que Rx.

 using System.Collections.Async; static IAsyncEnumerable ProduceItems(string[] urls) { return new AsyncEnumerable(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); }); } 

Había un plan para hacer

https://github.com/dotnet/csharplang/issues/43

Pero actualmente no es posible

En primer lugar, tenga en cuenta que las cosas Async no están terminadas. El equipo C # todavía tiene un largo camino por recorrer antes de que C # 5 sea lanzado.

Dicho esto, creo que es posible que desee recostackr las tareas que se están desencadenando en la función DownloadAllHtml de una manera diferente.

Por ejemplo, puedes usar algo como esto:

 IEnumerable> DownloadAllUrl(string[] urls) { foreach(var url in urls) { yield return DownloadHtmlAsync(url); } } async Task DownloadHtmlAsync(url) { // Do your downloading here... } 

No es que la función DownloadAllUrl NO sea una llamada asincrónica. Pero puede hacer que la llamada asincrónica se implemente en otra función (es decir, DownloadHtmlAsync ).

La Biblioteca de tareas paralelas tiene las funciones .ContinueWhenAny y .ContinueWhenAll .

Eso se puede usar así:

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

El rendimiento no funciona con la espera, desafortunadamente. Pero esto es para lo que es Rx. Consulte https://msdn.microsoft.com/library/hh242985

Esta solución funciona como se esperaba. Observe la parte 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; } } }