19

AsyncTask が内部でどのように機能するかを知りたいです。

Java Executorを使用して操作を実行していることはわかっていますが、まだ理解できない質問がいくつかあります。お気に入り:

  1. Androidアプリで一度にいくつのAsyncTaskを開始できますか?
  2. 10 個の AsyncTask を開始すると、すべてのタスクが同時に実行されますか、それとも 1 つずつ実行されますか?

同じことをテストするために、75000 AsyncTask を試しました。問題はありません。すべてのタスクがスタックにプッシュされ、1 つずつ実行されるようです。

また、100000 AsyncTasks を開始すると、OutOfMemoryError が発生し始めます。

一度に実行できる AsyncTask の数に制限はありますか?

注: SDK 4.0 でこれらをテストしました

4

4 に答える 4

33

AsyncTaskかなり長い話があります。

Cupcake (1.5) で初めて登場したときは、1 つの追加スレッド (1 つずつ) でバックグラウンド操作を処理していました。Donut (1.6) では変更され、スレッドのプールが使用されるようになりました。また、プールが使い果たされるまで、複数の操作を同時に処理できました。このような場合、操作はキューに入れられました。

Honeycomb のデフォルトの動作は、単一のワーカー スレッド (1 つずつ処理) を使用するように切り替えられているためです。しかし、新しいメソッド ( executeOnExecutor ) が導入され、必要に応じて同時にタスクを実行できるようになりました (2 つの異なる標準のエグゼキュータがあります:SERIAL_EXECUTORTHREAD_POOL_EXECUTOR)。

タスクがキューに入れられる方法も、使用するエグゼキューターによって異なります。パラレルの場合は10個まで( )に制限されますnew LinkedBlockingQueue<Runnable>(10)。シリアルの場合は制限なし(new ArrayDeque<Runnable>())。

したがって、タスクの処理方法は、タスクの実行方法と実行する SDK バージョンによって異なります。スレッドの制限については保証されていませんが、ICS ソース コードを見ると、プール内のスレッドの数は範囲内で変動する可能性があると言えます5..128

デフォルトの方法で 100000 を起動すると、executeシリアル エグゼキュータが使用されます。すぐに処理できないタスクはキューに入れられるため、取得されますOutOfMemoryError(数千のタスクが配列でバックアップされたキューに追加されます)。

一度に開始できるタスクの正確な数は、実行しているデバイスのメモリ クラスと、使用するエグゼキュータによって異なります。

于 2012-05-07T11:04:25.970 に答える
4

AsyncTasks には、遅延タスクを格納するための固定サイズのキューが内部的にあります。デフォルトのキュー サイズは 10 です。たとえば、15 個のタスクを連続して開始した場合、最初の 5 個がタスクに入りますdoInBackground()が、残りはワーカー スレッドが解放されるまでキューで待機します。最初の 5 つのうちの 1 つが終了し、ワーカー スレッドが解放されると、キューのタスクが実行を開始します。この場合、最大 5 つのタスクが同時に実行されます。

はい、一度に実行できるタスクの数には制限があります。そのため、AsyncTask はワーカー スレッドの最大数が制限されたスレッド プール エグゼキューターを使用し、遅延タスク キューは固定サイズ 10 を使用します。ワーカー スレッドの最大数は 128 です。138 を超えるカスタム タスクを実行しようとすると、アプリケーションはRejectedExecutionExceptionをスローします。

于 2012-05-07T11:12:01.400 に答える
1
  1. Androidアプリで一度にいくつのAsyncTaskを開始できますか?

    AsyncTaskLinkedBlockingQueue容量が 10 のによってサポートされています (ICS およびジンジャーブレッド)。したがって、開始しようとしているタスクの数と終了までにかかる時間によって異なりますが、キューの容量を使い果たすことは間違いありません。

  2. 10 個の AsyncTask を開始すると、すべてのタスクが同時に実行されますか、それとも 1 つずつ実行されますか?

    繰り返しますが、これはプラットフォームによって異なります。最大プール サイズは、gingerbread と ICS の両方で 128 です - しかし、*デフォルトの動作* は 2.3 と 4.0 の間で変更されました - デフォルトの並列から直列に。ICS で並列に実行したい場合は、[executeOnExecutor][1] と組み合わせて呼び出す必要があります。THREAD_POOL_EXECUTOR

並列エグゼキューターに切り替えて、75 000 のタスク (シリアル impl) でスパムしてみてください。ArrayDeque容量の上限のないinternalがあります (OutOfMemoryExceptions ofc を除く)。

于 2012-05-07T11:04:34.913 に答える