AsyncTask utilizza un modello di pool di thread per eseguire le cose da doInBackground (). Il problema è inizialmente (nelle prime versioni del sistema operativo Android) che la dimensione del pool era solo 1, il che significa che non c'erano calcoli paralleli per un gruppo di AsyncTasks. Ma in seguito lo hanno risolto e ora la dimensione è 5, quindi al massimo 5 AsyncTask possono essere eseguiti contemporaneamente. Sfortunatamente non ricordo in quale versione esattamente l'hanno cambiata.
AGGIORNARE:
Ecco cosa dice l'attuale API (27-01-2012) su questo:
Alla prima introduzione, gli AsyncTask erano eseguiti in serie su un singolo thread in background. A partire da DONUT, questo è stato modificato in un pool di thread che consente a più attività di operare in parallelo. Dopo HONEYCOMB, si prevede di riportarlo in un singolo thread per evitare errori di applicazione comuni causati da un'esecuzione parallela. Se si desidera veramente l'esecuzione parallela, è possibile utilizzare la versione executeOnExecutor (Executor, Params ...) di questo metodo con THREAD_POOL_EXECUTOR; tuttavia, vedere i commenti lì per avvertenze sul suo utilizzo.
DONUT è Android 1.6, HONEYCOMB è Android 3.0.
AGGIORNAMENTO: 2
Vedi il commento di kabuko
da Mar 7 2012 at 1:27
.
Si scopre che per le API in cui viene utilizzato "un pool di thread che consente a più attività di operare in parallelo" (a partire da 1.6 e terminando su 3.0) il numero di AsyncTasks in esecuzione simultaneamente dipende da quante attività sono già state passate per l'esecuzione, ma non hanno ancora finito il loro doInBackground()
.
Questo è testato / confermato da me il 2.2. Supponiamo di avere un AsyncTask personalizzato che dorme solo un secondo doInBackground()
. AsyncTasks utilizza una coda di dimensioni fisse internamente per la memorizzazione di attività ritardate. La dimensione della coda è 10 per impostazione predefinita. Se inizi 15 attività personalizzate di seguito, le prime 5 inseriranno le loro doInBackground()
, ma il resto attenderà in coda un thread di lavoro gratuito. Non appena uno dei primi 5 termina e quindi rilascia un thread di lavoro, verrà avviata un'attività dalla coda. Quindi, in questo caso, verranno eseguite contemporaneamente al massimo 5 attività. Tuttavia, se avvii 16 attività personalizzate di seguito, le prime 5 entreranno nelle loro doInBackground()
, le restanti 10 entreranno in coda, ma per il 16 verrà creato un nuovo thread di lavoro in modo che inizi l'esecuzione immediatamente. Quindi, in questo caso, verranno eseguite contemporaneamente al massimo 6 attività.
Esiste un limite al numero di attività che possono essere eseguite contemporaneamente. Poiché AsyncTask
utilizza un esecutore di pool di thread con un numero massimo limitato di thread di lavoro (128) e la coda delle attività in ritardo ha dimensioni fisse 10, se si tenta di eseguire più di 138 attività personalizzate con cui si bloccherà l'app java.util.concurrent.RejectedExecutionException
.
A partire dalla 3.0 l'API consente di utilizzare il proprio esecutore del pool di thread personalizzato tramite il AsyncTask.executeOnExecutor(Executor exec, Params... params)
metodo. Ciò consente, ad esempio, di configurare la dimensione della coda delle attività ritardate se il valore predefinito 10 non è quello che ti serve.
Come menziona @Knossos, esiste un'opzione da utilizzare AsyncTaskCompat.executeParallel(task, params);
dalla libreria di supporto v.4 per eseguire attività in parallelo senza preoccuparsi del livello API. Questo metodo è diventato obsoleto nel livello API 26.0.0.
AGGIORNAMENTO: 3
Ecco una semplice app di prova per giocare con il numero di compiti, esecuzione seriale o parallela: https://github.com/vitkhudenko/test_asynctask
AGGIORNAMENTO: 4 (grazie @penkzhou per averlo segnalato)
A partire da Android 4.4 AsyncTask
si comporta diversamente da quanto descritto nella sezione AGGIORNAMENTO: 2 . Esiste una correzione per impedire la AsyncTask
creazione di troppi thread.
Prima di Android 4.4 (API 19) AsyncTask
c'erano i seguenti campi:
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) i campi sopra riportati sono cambiati in questo:
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);
Questa modifica aumenta la dimensione della coda a 128 elementi e riduce il numero massimo di thread al numero di core della CPU * 2 + 1. Le app possono comunque inviare lo stesso numero di attività.