【问题标题】:how to improve performance when tons of AsyncTasks running当大量 AsyncTask 运行时如何提高性能
【发布时间】:2014-12-01 05:59:31
【问题描述】:

我一直在写一个文件下载模块,当用户选择一些文件并点击下载按钮时,它会创建与文件一样多的 AsyncTasks。所有这些文件都被添加到一个数组中。然后我遍历数组,为文件创建一个AsyncTask,调用每个AsyncTask实例的execute方法。

我通过下载 20 张照片(每张 1 MB)来测试这个模块,结果它可以成功下载这些文件并且稳定。但是当我添加数千个文件(例如 2000 张照片)进行下载时,问题就来了。

当用户点击下载这 2000 张照片时,它会创建 2000 个 AsyncTasks 并立即调用每个的 execute 方法。我认为这不是最佳实践,甚至不会导致 OOM。因为它同时启动了 2000 个线程,虽然根据官方文档只有前 5 个 AsyncTask 实例会在 Kitkat 上调用它们的doInbackground 方法,但已经创建了 2000 个线程并分配了资源(对吗?),这可能会导致 OOM。

为了获得更好的性能,我计划在队列中管理这些 AsyncTask,只轮询前五个实例并执行它们,任何人都执行完毕,它会发送通知并轮询替代一个,直到所有剩余的 AsyncTask 都已执行。我想知道这样想是否正确。提前致谢!

添加下载任务的方法

/**
 * Add a new download task
 */
public int addDownloadTask(Account account,
                           String repoName,
                           String repoID,
                           String path) {
    // omit lines...
    DownloadTask task = new DownloadTask(account, repoName, repoID, path);
    // execute download task serially
    task.execute();
    return task.getTaskID();
}

循环调用addDownloadTask

for (SeafDirent seafDirent : dirents) {
            if (!seafDirent.isDir()) {
                File localCachedFile = dataManager.getLocalCachedFile(repoName, repoID, seafDirent.name), seafDirent.id);
                if (localCachedFile == null) {
                    txService.addDownloadTask(account, repoName, repoID, Utils.pathJoin(filePath, seafDirent.name));
                }
            }
        }

【问题讨论】:

  • 这样思考的好方法。如果你不介意,可以在这里放一些代码,以便我了解一下。
  • 为什么不触发 2000 个 AsyncTask,而是触发一个遍历每次下载的 AsyncTask?
  • 你有没有想过一个线程池可以按照你想要的方式管理队列?或者你需要异步任务的 UIRunning 方法吗?这样您就不必重新创建新异步任务的实例 1999 次。会对性能产生影响..
  • 我认为迈克的评论很好。我认为很好的技术。
  • @Mike 我需要分别发布下载进度,我使用taskID作为标识符,从上面的代码可以看出。

标签: java android multithreading android-asynctask


【解决方案1】:

您应根据自己的要求创建自己的Queue 及其Executor 以管理Threads

请看example of ThreadPool creation to manage multiple threadsThreadPoolThreadPool Executor

【讨论】:

  • 感谢您的评论,这个例子是关于管理可运行类型但AsyncTask,所以我想知道是否可以重写它
  • @LoganGuoz:AsyncTask 只不过是一个线程,Runnable 也是如此。 Android 框架使用ThreadPoolExecutor 来管理预定义的线程数,如果您按照示例中所述创建自己的ThreadPoolExecutor,则可以指定您的限制。
  • 我对如何从 Asynctask 转换为 Runnable 类型感到困惑
  • @LoganGuo:你在AsyncTaskdoInBackground写的任何东西都应该写在runRunnable的方法中
  • @LoganGuo:下载this example看看PhotoDownloadRunnable.java的代码
【解决方案2】:

异步任务使用线程池执行器模式。并发运行的任务不能超过 128 个。

这个帖子解释得很清楚: Running multiple AsyncTasks at the same time -- not possible?

但是,您的问题是关于创建异步任务实例(本质上是对象)。当您在循环中创建对象时,肯定会出现系统内存不足的情况。

我还认为 OOM 更有可能发生,因为该大小的图像被加载到内存中,而不是对象创建。你可能想使用弱引用 (http://android-developers.blogspot.in/2010/07/multithreading-for-performance.html)

【讨论】:

    【解决方案3】:

    试试bolts框架,它来自facebook和parse,主要目的是帮助你管理你的任务。

    https://github.com/BoltsFramework/Bolts-Android

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-03
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-18
      • 1970-01-01
      相关资源
      最近更新 更多