同时运行多个 AsyncTasks —— 不可能? [英] Running multiple AsyncTasks at the same time -- not possible?

查看:24
本文介绍了同时运行多个 AsyncTasks —— 不可能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试同时运行两个 AsyncTask.(平台为Android 1.5,HTC Hero.)但是,只有第一个被执行.这是描述我的问题的简单片段:

I'm trying to run two AsyncTasks at the same time. (Platform is Android 1.5, HTC Hero.) However, only the first gets executed. Here's a simple snippet to describe my problem:

public class AndroidJunk extends Activity {
 class PrinterTask extends AsyncTask<String, Void, Void> {
     protected Void doInBackground(String ... x) {
      while (true) {
       System.out.println(x[0]);
       try {
        Thread.sleep(1000);
       } catch (InterruptedException ie) {
        ie.printStackTrace();
       }
      }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        new PrinterTask().execute("bar bar bar");
        new PrinterTask().execute("foo foo foo");

        System.out.println("onCreate() is done.");
    }
}

我期望的输出是:

onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo

等等.但是,我得到的是:

And so on. However, what I get is:

onCreate() is done.
bar bar bar
bar bar bar
bar bar bar

第二个 AsyncTask 永远不会被执行.如果我更改 execute() 语句的顺序,则只有 foo 任务会产生输出.

The second AsyncTask never gets executed. If I change the order of the execute() statements, only the foo task will produce output.

我是否在这里遗漏了一些明显的东西和/或做了一些愚蠢的事情?不能同时运行两个 AsyncTask 吗?

Am I missing something obvious here and/or doing something stupid? Is it not possible to run two AsyncTasks at the same time?

我意识到有问题的手机运行的是 Android 1.5,我更新了问题描述.因此.我在运行 Android 2.1 的 HTC Hero 上没有这个问题.嗯……

I realized the phone in question runs Android 1.5, I updated the problem descr. accordingly. I don't have this problem with an HTC Hero running Android 2.1. Hmmm ...

推荐答案

AsyncTask 使用线程池模式来运行 doInBackground() 中的内容.问题最初是(在早期的 Android 操作系统版本中)池大小仅为 1,这意味着一堆 AsyncTask 没有并行计算.但是后来他们修复了这个问题,现在大小是 5,所以最多可以同时运行 5 个 AsyncTask.不幸的是,我不记得他们在哪个版本中改变了这一点.

AsyncTask uses a thread pool pattern for running the stuff from doInBackground(). The issue is initially (in early Android OS versions) the pool size was just 1, meaning no parallel computations for a bunch of AsyncTasks. But later they fixed that and now the size is 5, so at most 5 AsyncTasks can run simultaneously. Unfortunately I don't remember in what version exactly they changed that.

更新:

以下是当前 (2012-01-27) API 对此的说明:

Here is what current (2012-01-27) API says on this:

首次引入时,AsyncTasks 在单个后台线程上串行执行.从 DONUT 开始,这已更改为允许多个任务并行操作的线程池.HONEYCOMB 之后,计划将其改回单线程,以避免并行执行导致的常见应用程序错误.如果你真的想要并行执行,你可以使用这个方法的 executeOnExecutor(Executor, Params...) 版本和 THREAD_POOL_EXECUTOR;但是,请参阅那里的评论以了解有关其使用的警告.

When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. After HONEYCOMB, it is planned to change this back to a single thread to avoid common application errors caused by parallel execution. If you truly want parallel execution, you can use the executeOnExecutor(Executor, Params...) version of this method with THREAD_POOL_EXECUTOR; however, see commentary there for warnings on its use.

甜甜圈是安卓 1.6,蜂巢是安卓 3.0.

DONUT is Android 1.6, HONEYCOMB is Android 3.0.

更新:2

请参阅 kabuko 来自 Mar 7 2012 at 1:27 的评论.

See the comment by kabuko from Mar 7 2012 at 1:27.

事实证明,对于使用允许多个任务并行操作的线程池"(从 1.6 开始到 3.0 结束)的 API,同时运行的 AsyncTask 的数量取决于已传递执行的任务数量已经,但还没有完成他们的doInBackground().

It turns out that for APIs where "a pool of threads allowing multiple tasks to operate in parallel" is used (starting from 1.6 and ending on 3.0) the number of simultaneously running AsyncTasks depends on how many tasks have been passed for execution already, but have not finished their doInBackground() yet.

这是我在 2.2 上测试/确认的.假设您有一个自定义的 AsyncTask,它只在 doInBackground() 中休眠一秒钟.AsyncTasks 在内部使用固定大小的队列来存储延迟任务.队列大小默认为 10.如果您连续启动 15 个自定义任务,那么前 5 个将进入它们的 doInBackground(),但其余的将在队列中等待空闲的工作线程.一旦前 5 个任务中的任何一个完成,从而释放一个工作线程,队列中的任务将开始执行.所以在这种情况下,最多 5 个任务将同时运行.但是,如果您连续启动 16 个自定义任务,那么前 5 个将输入它们的 doInBackground(),其余 10 个将进入队列,但第 16 个将创建一个新的工作线程,因此它会立即开始执行.所以在这种情况下,最多会同时运行 6 个任务.

This is tested/confirmed by me on 2.2. Suppose you have a custom AsyncTask that just sleeps a second in doInBackground(). AsyncTasks use a fixed size queue internally for storing delayed tasks. Queue size is 10 by default. If you start 15 your custom tasks in a row, then first 5 will enter their doInBackground(), but the rest will wait in a queue for a free worker thread. As soon as any of the first 5 finishes, and thus releases a worker thread, a task from the queue will start execution. So in this case at most 5 tasks will run simultaneously. However if you start 16 your custom tasks in a row, then first 5 will enter their doInBackground(), the rest 10 will get into the queue, but for the 16th a new worker thread will be created so it'll start execution immediately. So in this case at most 6 tasks will run simultaneously.

可以同时运行多少个任务是有限制的.由于 AsyncTask 使用线程池执行器,其最大工作线程数有限 (128) 并且延迟任务队列的大小固定为 10,如果您尝试执行超过 138 个自定义任务,应用程序将崩溃java.util.concurrent.RejectedExecutionException.

There is a limit of how many tasks can be run simultaneously. Since AsyncTask uses a thread pool executor with limited max number of worker threads (128) and the delayed tasks queue has fixed size 10, if you try to execute more than 138 your custom tasks the app will crash with java.util.concurrent.RejectedExecutionException.

从 3.0 开始,API 允许通过 AsyncTask.executeOnExecutor(Executor exec, Params... params) 方法使用您的自定义线程池执行器.例如,如果默认 10 不是您需要的,这允许配置延迟任务队列的大小.

Starting from 3.0 the API allows to use your custom thread pool executor via AsyncTask.executeOnExecutor(Executor exec, Params... params) method. This allows, for instance, to configure the size of the delayed tasks queue if default 10 is not what you need.

正如@Knossos 所提到的,可以选择使用 AsyncTaskCompat.executeParallel(task, params); 来自 support v.4 库来并行运行任务,而无需担心 API 级别.此方法在 API 级别 26.0.0 中已弃用.

As @Knossos mentions, there is an option to use AsyncTaskCompat.executeParallel(task, params); from support v.4 library to run tasks in parallel without bothering with API level. This method became deprecated in API level 26.0.0.

更新:3

这是一个简单的测试应用程序,用于处理多个任务,串行与并行执行:https://github.com/vitkhudenko/test_asynctask

Here is a simple test app to play with number of tasks, serial vs. parallel execution: https://github.com/vitkhudenko/test_asynctask

更新:4(感谢@penkzhou 指出这一点)

UPDATE: 4 (thanks @penkzhou for pointing this out)

从 Android 4.4 开始 AsyncTask 的行为与 UPDATE: 2 部分中描述的有所不同.有修复以防止AsyncTask 创建过多线程.

Starting from Android 4.4 AsyncTask behaves differently from what was described in UPDATE: 2 section. There is a fix to prevent AsyncTask from creating too many threads.

在 Android 4.4 (API 19) 之前,AsyncTask 有以下字段:

Before Android 4.4 (API 19) AsyncTask had the following fields:

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(10);

在 Android 4.4 (API 19) 中,上述字段更改为:

In Android 4.4 (API 19) the above fields are changed to this:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

此更改将队列的大小增加到 128 个项目,并将最大线程数减少到 CPU 内核数 * 2 + 1.应用程序仍然可以提交相同数量的任务.

This change increases the size of the queue to 128 items and reduces the maximum number of threads to the number of CPU cores * 2 + 1. Apps can still submit the same number of tasks.

这篇关于同时运行多个 AsyncTasks —— 不可能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆