2016-06-01 11 views
1

Ich bin auf der Suche nach einer einfachen Möglichkeit, mehrere Aufgaben parallel zu starten und warten auf alle von ihnen abzuschließen.Kotlin/anko mehrere asynchrone Aufgaben

Betrachten Sie diese C# Beispiel:

private static void Main(string[] args) 
{ 
    var urlList = new[] {"http://www.microsoft.com/", "http://www.google.com/", "http://www.apple.com/" }; 
    var result = GetHtml(urlList); 
} 

private static List<string> GetHtml(string[] urlList) 
{ 
    var tasks = new List<Task>(); 
    var output = new List<string>(); 

    foreach (var url in urlList) 
    { 
     var task = new Task(() => 
     { 
      var html = new WebClient().DownloadString(url); 
      output.Add(html); 
     }); 

     tasks.Add(task); 

     //starts task in a separate thread (doesn't block anything) 
     task.Start(); 
    } 

    //waits for all tasks (running in parallel) to complete before exiting method 
    Task.WaitAll(tasks.ToArray()); 

    return output; 
} 

getHTML Methode mehrere Web-Seiten parallel herunterlädt und gibt eine Liste von HTML-Strings.

Wie kann ich dies mit Kotlin/Anko erreichen?

private fun GetHtml(urlList: Array<String>): ArrayList<String> { 

    val tasks = ArrayList<Future<Unit>>() 
    val output = ArrayList<String>() 

    for (url in urlList) { 
     val task = async() { 
      //some java-code that downloads html from <url>, doesn't matter for now 
      output.add("html for $url") 
     } 
     tasks.add(task) 
    } 

    //this is NOT parallel execution 
    for (task in tasks) { 
     task.get()   
    } 

    //tasks.getall() ?? 

    return output 
} 
+1

Vielleicht gibt es einen besseren Weg, aber Sie können [einen 'ExecutorService' für' async' angeben] (https://github.com/Kotlin/anko/blob/master/doc/ADVANCED .md # asynchronous-tasks) und 'ExecutorService' hat eine [' awaitTermination'-Methode] (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#awaitTermination (lang,% 20java.util.concurrent.TimeUnit)). – Michael

+1

Mit Kotlin 1.1.1 können Sie einen oder mehrere Jobs "erwarten", siehe http://StackOverflow.com/a/43151714/882912 – KTCO

Antwort

1

Basierend auf Eingaben von Michael und pdegand59, hier ist eine Arbeitslösung:

private fun GetHtml(urlList: Array<String>): ArrayList<String> { 

    val pool = Executors.newFixedThreadPool(urlList.count()) 
    val countDownLatch = CountDownLatch(urlList.count()) 

    val output = ArrayList<String>() 

    for (url in urlList) { 

     async(pool, { 
      //some java-code that downloads html for <url> 
      output.add("html for $url") 
      countDownLatch.countDown() 
     })  
    } 

    countDownLatch.await() 

    return output 
} 
0

Ich würde vorschlagen, CountDownLatch in einem separaten Thread verwenden, um den Haupt-Thread während alles parallelen Downloads nicht blockiert :

private fun downloadAllHtml(urlList: Array<String>) { 
    val output = ArrayList<String>() 
    val countDownLatch = CountDownLatch(urlList.length) 

    async(Executors.newSingleThreadExecutor() { 
    countDownLatch.await() 
    uiThread { 
     onAllHtmlDownloaded(output) 
    } 
    } 

    urlList.forEach { url: String -> 
    async() { 
     // download stuff 
     output.add("stuff downloaded") 
     countDownLatch.countDown() 
    } 
    } 
    // this method ends instantly, not blocking the main thread 
} 

private fun onAllHtmlDownloaded(output: ArrayList<String>) { 
    // all your html, on the main thread 
} 

Sie müssen möglicherweise etwas Versuch/Fang hinzufügen. Die IDE wird dir helfen;)

+0

CountDownLatch sieht gut aus, aber der von Ihnen bereitgestellte Code funktioniert leider nicht. Die Methode onAllHtmlDownloaded wird niemals erreicht, da countDownLatch.await() den Prozess auf unbestimmte Zeit wartet. Was ich getan habe, war einen separaten ThreadPool zu erstellen und countDownLatch.await() zu verwenden, das hat gut funktioniert. – Fire095

+0

Ich habe den Code aktualisiert, indem ich den async-Aufruf mit have vor der Schleife verschoben habe und diesen Async auf einem anderen Executor ausgeführt habe. – pdegand59

+0

Danke für Ihre Eingabe! Das Problem liegt hier nicht in der CountDownLatch, sondern in async() Blöcken, die HTML herunterladen. Das Blockieren des Hauptthreads ist in diesem Szenario kein Problem, also lass es so einfach wie möglich sein :) Ich habe meine Antwort aktualisiert und dir Kredit gegeben – Fire095

Verwandte Themen