10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Androidの主要画像系ライブラリのTread Poolをみる

Last updated at Posted at 2017-01-18

Androidで画像の非同期読み込みするスレッドを管理をしたくなったので、参考に調べた主要な画像系ライブラリのTread Pool周りのメモです。
調べ方は各ライブラリのレポジトリでExecutorThreadPoolExecutor などで検索してヒットしたものを載せています。(詳しく読み込んでいないので、細かい動作による初期値の変化についてはあまり触れません)

※調べたのは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を変更しています。

PicassoExecutorService.java

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に置き換わっています。

FifoPriorityThreadPoolExecutor.java
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です。

GlideBuulder.java

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を分けており、探すのが大変でした…これが正確でない場合はコメントいただきたいです。スレッド数以外は特に指定していないのでExecutorServicenewFixedThreadPoolで指定される値が入るようです。

HttpUrlConnectionNetworkFetcher.java
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

AsyncTask.java
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


参考になる記事を見つけたら貼ります
モバイルアプリのスレッドプールサイズの最適化(画像読み込み編)

10
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?