Androidで画像の非同期読み込みするスレッドを管理をしたくなったので、参考に調べた主要な画像系ライブラリのTread Pool周りのメモです。
調べ方は各ライブラリのレポジトリでExecutor
、ThreadPoolExecutor
などで検索してヒットしたものを載せています。(詳しく読み込んでいないので、細かい動作による初期値の変化についてはあまり触れません)
※調べたのはExecutorを自分で設定しない場合のデフォルトの値です。
今回調べた対象は以下のライブラリです。
早見表
比較用にAsyncTask
も調べました。
picasso | glide | fresco | AsyncTask | |
---|---|---|---|---|
core pool size | 1~4 | 1~ CPU数 | 3 | 2~4 |
maximum pool size | 同上 | 同上 | 同上 | 1~ (CPU数 * 2 + 1) |
work queue size | 11 | Integer.MAX_VALUE | Integer.MAX_VALUE | 128 |
queue | PriorityBlockingQueue | PriorityBlockingQueue | LinkedBlockingQueue | LinkedBlockingQueue |
CPU数はRuntime.getRuntime().availableProcessors() の値です |
上の表だけでは説明が不十分なのでそれぞれ少しだけ補足します。
picasso
参照クラスはこちら
PicassoExecutorService
picassoはデフォルトでは3ですが、WiFiでは4にするなど通信状況に応じてpool sizeを変更しています。
private static final int DEFAULT_THREAD_COUNT = 3;
void adjustThreadCount(NetworkInfo info) {
if (info == null || !info.isConnectedOrConnecting()) {
setThreadCount(DEFAULT_THREAD_COUNT);
return;
}
switch (info.getType()) {
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
case ConnectivityManager.TYPE_ETHERNET:
setThreadCount(4);
break;
case ConnectivityManager.TYPE_MOBILE:
switch (info.getSubtype()) {
case TelephonyManager.NETWORK_TYPE_LTE: // 4G
case TelephonyManager.NETWORK_TYPE_HSPAP:
case TelephonyManager.NETWORK_TYPE_EHRPD:
setThreadCount(3);
break;
case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
setThreadCount(2);
break;
case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
case TelephonyManager.NETWORK_TYPE_EDGE:
setThreadCount(1);
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
}
Glide
参照クラスはこちら
FifoPriorityThreadPoolExecutor.java
GlideBuilder.java
3系以前はGlideExecutor
というクラスでしたが、FifoPriorityThreadPoolExecutor
に置き換わっています。
public FifoPriorityThreadPoolExecutor(int poolSize) {
this(poolSize, UncaughtThrowableStrategy.LOG);
}
public FifoPriorityThreadPoolExecutor(int poolSize, UncaughtThrowableStrategy uncaughtThrowableStrategy) {
this(poolSize, poolSize, 0, TimeUnit.MILLISECONDS, new DefaultThreadFactory(),
uncaughtThrowableStrategy);
}
public FifoPriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAlive, TimeUnit timeUnit,
ThreadFactory threadFactory, UncaughtThrowableStrategy uncaughtThrowableStrategy) {
super(corePoolSize, maximumPoolSize, keepAlive, timeUnit, new PriorityBlockingQueue<Runnable>(), threadFactory);
this.uncaughtThrowableStrategy = uncaughtThrowableStrategy;
}
コンストラクタはこのようになっており、poolSize == maximumPoolSize
になるようですね。
このコンストラクタを呼び出しているのはGlideBuilder
です。
…
Glide createGlide() {
if (sourceService == null) {
final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
sourceService = new FifoPriorityThreadPoolExecutor(cores);
}
if (diskCacheService == null) {
diskCacheService = new FifoPriorityThreadPoolExecutor(1);
}
…
return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
}
sourceService
が画像読み込みに使われるプールです。よってここでは1~ availableProcessorsの数ですね。
fresco
参照クラスはこちら
HttpUrlConnectionNetworkFetcher.java
frescoではファイルIOやデコード、バックグラウンド処理など細かくExecutorを分けており、探すのが大変でした…これが正確でない場合はコメントいただきたいです。スレッド数以外は特に指定していないのでExecutorService
のnewFixedThreadPool
で指定される値が入るようです。
private static final int NUM_NETWORK_THREADS = 3;
public HttpUrlConnectionNetworkFetcher() {
this(Executors.newFixedThreadPool(NUM_NETWORK_THREADS));
}
@VisibleForTesting
HttpUrlConnectionNetworkFetcher(ExecutorService executorService) {
mExecutorService = executorService;
}
AsyncTask
※APIレベルによって挙動が異なるので詳しくはドキュメントを読んでください
https://developer.android.com/reference/android/os/AsyncTask.html
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
実装を見る限りとても便利ですが、使用する上でいくつか注意点はあります。
@hkurokawa さんのこちら資料が参考になりました。
http://www.slideshare.net/hiroshikurokawa79/asynctask
参考になる記事を見つけたら貼ります
モバイルアプリのスレッドプールサイズの最適化(画像読み込み編)