Je dois lancer un certain nombre d'emplois qui retourneront un résultat. P>
dans le code principal (qui est pas em> a coroutine), après avoir lancé les travaux, j'ai besoin d'attendre que tous remplir leur tâche Si je sors de l'attente parce que tous les emplois sont terminés avant le délai d'attente, c'est génial, je collectionnerai leurs résultats. P>
Mais si certains des emplois prennent plus de temps que le délai d'attente, ma fonction principale doit se réveiller dès que le délai d'expiration expire, inspectez les emplois terminés à temps (le cas échéant) et lesquels sont toujours en cours d'exécution et fonctionnent de Là, sans em> annule les travaux qui fonctionnent toujours. P>
Comment voudriez-vous coder ce genre d'attente? P>
3 Réponses :
Merci. Mais comment votre code se comporte-t-il dans des cas de bord? Lorsque La déporedlist code> est vide, par exemple, ou lorsque tous les travaux se terminent avant le délai d'attente?
En outre, pourquoi runblocking code> découragé et où l'avez-vous lu?
Voici la solution que j'ai proposée. Associant chaque travail avec un état (entre autres): et écrire une boucle explicite: p> L'état initial est appelé attente (au lieu de courir) parce que cela ne signifie pas nécessairement que le travail est toujours en cours d'exécution, seulement que ma boucle n'a pas encore pris en compte. P> Je suis intéressé à savoir si cela est assez idiomatique, ou s'il y a de meilleurs moyens de coder ce type de comportement. p> p>
La solution suit directement de la question. Premièrement, nous concevons une fonction de suspension pour la tâche. Voyons nos exigences:
Si certains des emplois prennent plus de temps que le délai d'attente ... sans annuler les travaux qui fonctionnent toujours. P> blockQuote>
Cela signifie que les travaux que nous avons lancés doivent être autonomes (non enfants), nous allons donc vous désactiver la concurrence structurée et utiliser
globalscope code> pour les lancer, collectant manuellement tout les emplois. Nous utilisons
async code> COROUTINE CONSTRUILDER, car nous prévoyons de collecter leurs résultats de certains types
R code> ultérieurement: p>
xxx pré> Après avoir lancé les emplois, j'ai besoin de les attendre pour tous remplir leur tâche ou pour un délai donné pour expirer, selon la première éventualité. P> blockQuote>
Attendons-les tous et faites-le en attente avec le délai d'attente: p>
xxx pré> Nous utilisons
joinall code> (par opposition à attendu code>) Pour éviter d'exception si l'un des travaux échoue et
avectimeOutNull code> pour éviter l'exception sur le délai d'attente. P>
Ma fonction principale doit se réveiller dès que le délai d'expiration expire, inspecter les emplois terminés à temps (le cas échéant) et lesquels sont toujours en cours d'exécution p> blockQuote>
xxx pré> dans le code principal (qui n'est pas une coroutine) ... p> BlockQuote>
Étant donné que notre code principal n'est pas une coroutine, il doit attendre de manière bloquante, donc nous comblions le code que nous avons écrit à l'aide de
Runblocking code>. Mettre tout ensemble: P>
fun awaitResultsWithTimeoutBlocking( timeoutMillis: Long, numberOfJobs: Int ) = runBlocking { val jobs: List<Deferred<R>> = List(numberOfJobs) { GlobalScope.async { /* our code that produces R */ } } withTimeoutOrNull(timeoutMillis) { jobs.joinAll() } jobs.map { deferred -> /* ... inspect results */ } }