AsyncTask verwendet ein Thread-Pool-Muster zum Ausführen des Materials von doInBackground (). Das Problem ist zunächst (in frühen Android-Betriebssystemversionen), dass die Poolgröße nur 1 betrug, was bedeutet, dass für eine Reihe von AsyncTasks keine parallelen Berechnungen durchgeführt wurden. Aber später haben sie das behoben und jetzt ist die Größe 5, so dass höchstens 5 AsyncTasks gleichzeitig ausgeführt werden können. Leider kann ich mich nicht erinnern, in welcher Version sie das genau geändert haben.
AKTUALISIEREN:
Hier ist, was die aktuelle (2012-01-27) API dazu sagt:
Bei der ersten Einführung wurden AsyncTasks seriell auf einem einzelnen Hintergrundthread ausgeführt. Beginnend mit DONUT wurde dies in einen Thread-Pool geändert, sodass mehrere Aufgaben gleichzeitig ausgeführt werden können. Nach HONEYCOMB ist geplant, dies wieder in einen einzelnen Thread zu ändern, um häufige Anwendungsfehler zu vermeiden, die durch parallele Ausführung verursacht werden. Wenn Sie wirklich eine parallele Ausführung wünschen, können Sie die Version executeOnExecutor (Executor, Params ...) dieser Methode mit THREAD_POOL_EXECUTOR verwenden. Im Kommentar finden Sie jedoch Warnungen zu seiner Verwendung.
DONUT ist Android 1.6, HONEYCOMB ist Android 3.0.
UPDATE: 2
Siehe den Kommentar von kabuko
von Mar 7 2012 at 1:27
.
Es stellt sich heraus, dass für APIs, bei denen "ein Pool von Threads verwendet wird, bei denen mehrere Aufgaben parallel ausgeführt werden können" (beginnend mit 1.6 und endend mit 3.0), die Anzahl der gleichzeitig ausgeführten AsyncTasks davon abhängt, wie viele Aufgaben bereits zur Ausführung übergeben wurden habe ihre doInBackground()
noch nicht beendet .
Dies wird von mir am 2.2 getestet / bestätigt. Angenommen, Sie haben eine benutzerdefinierte AsyncTask, die nur eine Sekunde lang schläft doInBackground()
. AsyncTasks verwenden intern eine Warteschlange mit fester Größe zum Speichern verzögerter Aufgaben. Die Warteschlangengröße beträgt standardmäßig 10. Wenn Sie 15 Ihrer benutzerdefinierten Aufgaben hintereinander starten, geben die ersten 5 ihre ein doInBackground()
, während der Rest in einer Warteschlange auf einen freien Arbeitsthread wartet. Sobald eine der ersten 5 beendet ist und somit ein Arbeitsthread freigegeben wird, beginnt die Ausführung einer Aufgabe aus der Warteschlange. In diesem Fall werden also höchstens 5 Aufgaben gleichzeitig ausgeführt. Wenn Sie jedoch 16 Ihre benutzerdefinierten Aufgaben hintereinander starten, werden zuerst 5 eingegeben doInBackground()
, die restlichen 10 werden in die Warteschlange gestellt. Für den 16. wird jedoch ein neuer Arbeitsthread erstellt, sodass die Ausführung sofort gestartet wird. In diesem Fall werden also höchstens 6 Aufgaben gleichzeitig ausgeführt.
Es gibt eine Begrenzung, wie viele Aufgaben gleichzeitig ausgeführt werden können. Da AsyncTask
ein Thread-Pool-Executor mit einer begrenzten maximalen Anzahl von Worker-Threads (128) verwendet wird und die Warteschlange für verzögerte Aufgaben die feste Größe 10 hat, stürzt die App ab, wenn Sie versuchen, mehr als 138 Ihrer benutzerdefinierten Aufgaben auszuführen java.util.concurrent.RejectedExecutionException
.
Ab 3.0 ermöglicht die API die Verwendung Ihres benutzerdefinierten Thread-Pool-Executors über die AsyncTask.executeOnExecutor(Executor exec, Params... params)
Methode. Auf diese Weise können Sie beispielsweise die Größe der Warteschlange für verzögerte Aufgaben konfigurieren, wenn Sie nicht die Standardeinstellung 10 benötigen.
Wie @Knossos erwähnt, gibt es eine Option AsyncTaskCompat.executeParallel(task, params);
aus der Support v.4-Bibliothek, um Aufgaben parallel auszuführen, ohne sich um die API-Ebene zu kümmern . Diese Methode wurde in API-Level 26.0.0 nicht mehr unterstützt.
UPDATE: 3
Hier ist eine einfache Test-App zum Spielen mit einer Reihe von Aufgaben, serielle oder parallele Ausführung: https://github.com/vitkhudenko/test_asynctask
UPDATE: 4 (danke @penkzhou für den Hinweis)
Ab Android 4.4 AsyncTask
verhält es sich anders als im Abschnitt UPDATE: 2 beschrieben . Es gibt eine Korrektur , um zu verhindern, AsyncTask
dass zu viele Threads erstellt werden.
Vor Android 4.4 (API 19) gab AsyncTask
es folgende Felder:
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);
In Android 4.4 (API 19) werden die obigen Felder folgendermaßen geändert:
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);
Diese Änderung erhöht die Größe der Warteschlange auf 128 Elemente und reduziert die maximale Anzahl von Threads auf die Anzahl von CPU-Kernen * 2 + 1. Apps können weiterhin dieselbe Anzahl von Aufgaben senden.