Les blocs d'itérateur réguliers (c'est-à-dire "yield return") sont-ils incompatibles avec "async" et "await"?
Cela donne une bonne idée de ce que j'essaie de faire:
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;
}
Cependant, j'obtiens une erreur du compilateur citant "impossible de charger la chaîne de message à partir des ressources".
Voici une autre tentative:
async Task<IEnumerable<Foo>> Method(String [] Strs)
{
foreach(var str in strs)
{
yield return await DoSomethingAsync( str)
}
}
Mais encore une fois, le compilateur renvoie une erreur: "impossible de charger la chaîne de message à partir des ressources".
Voici le vrai code de programmation de mon projet
Ceci est très utile lorsque j'ai une tâche de liste, cette tâche peut être télécharger du HTML à partir d'une URL et j'utilise la syntaxe "yield return wait task", le résultat est que je veux IEnumerable<Foo>
. Je ne veux pas écrire ce code:
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;
}
Mais il semble que je dois le faire.
Merci pour toute aide.
la source
IAsyncEnumerator<T>
type défini par Arne.Réponses:
Ce que vous décrivez peut être accompli avec la
Task.WhenAll
méthode. Remarquez comment le code se transforme en une simple ligne unique. Ce qui se passe, c'est que chaque URL individuelle commence le téléchargement, puisWhenAll
est utilisée pour combiner ces opérations en une seuleTask
qui peut être attendue.la source
async
de la méthode et faitesreturn Task.WhenAll
directement.urls.Select(DownloadHtmlAsync)
Is it possible to await yield?
vous venez de trouver une solution pour ce cas d'utilisation. N'a pas répondu à la question générale.Task<string[]>
car cela indiquerait que vous ne retournez plus un itérateur avec une exécution différée, c'est-à-dire. toutes les URL sont en cours de téléchargement.tl; dr Les itérateurs implémentés avec yield sont une construction bloquante, donc à partir de maintenant, wait et yield sont incompatibles.
Long Puisque l'itération sur un
IEnumerable
est une opération bloquante, appeler une méthode marquée commeasync
l'exécutera toujours de manière bloquante, car elle doit attendre que l'opération se termine.L'attente
Method
mélange des significations. Voulez-vous attendre que leTask
ait unIEnumerable
, puis bloquer son itération? Ou essayez-vous d'attendre chaque valeur duIEnumerable
?Je suppose que le second est le comportement souhaité et dans ce cas, la sémantique Iterator existante ne fonctionnera pas. L'
IEnumerator<T>
interface est essentiellementJ'ignore
Reset()
car cela n'a aucun sens pour une séquence de résultats asynchrones. Mais ce dont vous auriez besoin est quelque chose comme ceci:Bien sûr,
foreach
cela ne fonctionnera pas non plus et vous devrez itérer manuellement comme ceci:la source
foreach
prise en charge de votre hypothétiqueIAsyncEnumerator<T>
?Selon les nouvelles fonctionnalités de C # 8.0 ( lien # 1 et lien # 2 ), nous aurons un
IAsyncEnumerable<T>
support d'interface qui permettra d'implémenter votre deuxième tentative. Il ressemblera à ceci:Nous pouvons obtenir le même comportement en C # 5 mais avec une sémantique différente:
La réponse de Brian Gideon implique que le code appelant obtiendra de manière asynchrone une collection de résultats obtenus en parallèle. Le code ci-dessus implique que le code appelant obtiendra des résultats comme à partir d'un flux un par un de manière asynchrone.
la source
Je sais que je suis trop tard avec la réponse, mais voici une autre solution simple qui peut être obtenue avec cette bibliothèque:
GitHub: https://github.com/tyrotoxin/AsyncEnumerable
NuGet.org: https: //www.nuget .org / packages / AsyncEnumerator /
C'est beaucoup plus simple que Rx.
la source
Cette fonctionnalité sera disponible à partir de C # 8.0. https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/
Depuis MSDN
Flux asynchrones
La fonctionnalité async / await de C # 5.0 vous permet de consommer (et de produire) des résultats asynchrones dans un code simple, sans callback:
Ce n'est pas si utile si vous souhaitez consommer (ou produire) des flux continus de résultats, tels que vous pourriez obtenir d'un appareil IoT ou d'un service cloud. Les flux asynchrones sont là pour cela.
Nous introduisons IAsyncEnumerable, qui est exactement ce à quoi vous vous attendez; une version asynchrone de IEnumerable. Le langage vous permet d'attendre chacun d'eux pour consommer leurs éléments, et leur rapporter pour produire des éléments.
la source
Il y avait un plan à faire
https://github.com/dotnet/csharplang/issues/43
Mais actuellement ce n'est pas possible
la source
Tout d'abord, gardez à l'esprit que le truc Async n'est pas terminé. L'équipe C # a encore un long chemin à parcourir avant la sortie de C # 5.
Cela étant dit, je pense que vous voudrez peut-être rassembler les tâches qui sont déclenchées dans la
DownloadAllHtml
fonction d'une manière différente.Par exemple, vous pouvez utiliser quelque chose comme ceci:
Non pas que la
DownloadAllUrl
fonction ne soit PAS un appel asynchrone. Mais, vous pouvez avoir l'appel async implémenté sur une autre fonction (ieDownloadHtmlAsync
).La bibliothèque parallèle de tâches a les fonctions
.ContinueWhenAny
et.ContinueWhenAll
.Cela peut être utilisé comme ceci:
la source
Task<IEnumerable<Task<string>>> DownloadAllUrl
. Ou, si vous voulez des actions de «pied de page»IEnumerable<Task>
. Eg gist.github.com/1184435async
tout est terminé et que C # 5.0 est publié, cela peut être mis à jour.Le rendement ne fonctionne pas avec wait, malheureusement. Mais c'est à cela que sert Rx. Consultez https://msdn.microsoft.com/library/hh242985
la source
Cette solution fonctionne comme prévu. Notez la
await Task.Run(() => enumerator.MoveNext())
partie.la source