【问题标题】:Kotlin/anko multiple async tasksKotlin/anko 多个异步任务
【发布时间】:2016-09-30 22:55:36
【问题描述】:

我正在寻找一种简单的方法来并行启动多个任务并等待所有任务完成。

考虑这个 c# 示例:

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 方法并行下载多个网页并返回一个 html 字符串列表。

如何使用 kotlin/anko 实现这一点?

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
}

【问题讨论】:

标签: android asynchronous kotlin anko


【解决方案1】:

根据Michaelpdegand59 的输入,这是一个可行的解决方案:

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
}

【讨论】:

    【解决方案2】:

    我建议在单独的线程中使用CountDownLatch,以避免在所有并行下载期间阻塞主线程:

    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
    }
    

    您可能需要添加一些 try/catch。 IDE 将帮助您 ;)

    【讨论】:

    • CountDownLatch 看起来不错,但不幸的是,您提供的代码不起作用。永远不会到达 onAllHtmlDownloaded 方法,因为 countDownLatch.await() 会导致进程无限期地等待。我所做的是创建一个单独的 ThreadPool 并使用 countDownLatch.await(),这很好。
    • 我更新了代码,在循环之前使用 await 移动异步调用并在另一个 Executor 上运行此异步。
    • 感谢您的意见!这里的问题不在于 CountDownLatch,而在于下载 html 的 async() 块。在这种情况下,阻塞主线程不是问题,所以让它尽可能简单:) 我已经更新了我的答案并给了你信用
    猜你喜欢
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多