okhttpのスレッド管理の考え方について

4171 ワード

最近Androidリクエストネットワークがヒットしていますが、公式に採用されているhttpリクエストライブラリはokhttpです.このライブラリの最適化がよく、効率が高いので、スレッドの管理を知りたいので、ソースコードを見てみました.
public synchronized ExecutorService executorService() {
 if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

khttp       ,               ,        Integer.MAX_VALUE,               ?

 private int maxRequests = 64;//       
  private int maxRequestsPerHost = 5;//           
  private final Deque readyAsyncCalls = new ArrayDeque<>();//                      ,        

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
runningAsyncCalls,      ,        。runningCallsForHost,             。          ,       maxRequests ,           maxRequestsPerHost  ,               。       maxRequests ,           maxRequestsPerHost  ,       readyAsyncCalls  ,     。             ?

/** Used by {@code AsyncCall#run} to signal completion. */
  synchronized void finished(AsyncCall call) {
    if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
    promoteCalls();
  }

    ,           ,      ,      promoteCalls();
private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

「スレッドのタスクが完了すると、runningAsyncCallsからこのリクエストが削除され、readyAsyncCallsで実行されていないタスクが実行されることがわかります.
このようなプロセス制御により、スレッドプールのサイズを64スレッド以内に制御し、同じホストのリクエストのスレッドを5つに制御することができ、同じプロジェクトでログと業務リクエストが同時に発生した場合、appの使用に影響を与えず、同時にサブスレッドの数を制御し、appの性能を保証することができる.
総じて,3つの集合を自分で維持することでスレッドプールのサイズを制御し,性能を最適化する.