Android OKhttp3 ディストリビュータのソースコード解析

OkHttp では、Dispatcher はネットワーク リクエストのスケジュールと実行を担当するコンポーネントです。同時リクエストの数とリクエストの優先順位を管理して基礎となる接続プールとスレッド プールを合理的に使用できるようにすることで、ネットワーク リクエストの効率パフォーマンス向上させます

デフォルトでは、OkHttp は最大 64 の同時リクエストを処理できるシングルトン ディスパッチャーを使用します。ディストリビュータをカスタマイズすることで、特定のニーズに合わせてこれらのデフォルト設定を変更することもできます。


非同期リクエストを例に挙げます。

package okhttp3;

final class RealCall implements Call {
  // ...

  @Override public void enqueue(Callback responseCallback) {
    // ...

    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
  // ...
}

Call.enqueue() を実行した後、Dispatcher.enqueue() を呼び出します。


package okhttp3;

public final class Dispatcher {
  private int maxRequests = 64;       // 最大请求数量
  private int maxRequestsPerHost = 5; // 同 Host 下最大请求数量

  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();   // 异步准备队列
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>(); // 异步执行队列
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();   // 同步执行队列

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call); // 线程池执行
    } else {
      readyAsyncCalls.add(call);
    }
  }
  // ...
}

Dispatcher は、各状態のタスク管理を容易にするために、各状態のタスクを保存する3 つの列を定義していることがわかりますDispatcher.enqueue()を呼び出した後、現在のリクエスト数に応じてタスクを実行するかどうかを制御し、現在のリクエスト数が多すぎる場合は、まず非同期待ちキューに格納されます。


待機キューに保存されているタスクはいつ優先されますか? まず、操作準備キューのメソッド Dispatcher.promoteCalls() を見てみましょう。

package okhttp3;

public final class Dispatcher {
  // ...

  private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // 是否达到最大请求次数
    if (readyAsyncCalls.isEmpty()) return; // 判断准备队列是否为空

    for (Iterator<AsyncCall> 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; // 是否达到最大请求次数
    }
  }
  // ...
}

このメソッドは、準備キューに未実行のタスクがあるかどうかを問い合わせ、存在する場合はスレッド プールで実行します。


このメソッドは非同期リクエストでいつ実行されますか?

package okhttp3;

final class RealCall implements Call {

  final class AsyncCall extends NamedRunnable {
    // ...

    @Override protected void execute() {
      try {
        // ...异步请求
      } catch (IOException e) {
        // ...异常处理
      } finally {
        client.dispatcher().finished(this); // 调用
      }
    // ...
  }
}


// Dispatcher

  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {

      if (promoteCalls) promoteCalls(); // 调用了 promoteCalls()
  }

非同期リクエストの後にcompleted() を呼び出した後、最終的に準備キューをポーリングして、未実行のタスクがあるかどうかを確認しますこれは、非同期リクエストの完全なフローです。

同期は比較的単純で、タスクを同期要求キューに直接追加しても開始されません。


概要: OkHttp のディストリビュータは、ネットワーク リクエスト プロセスで非常に重要な役割を果たし、同時リクエストを効果的に管理し、リクエストの順序と実行を最適化し、接続プールとスレッド プールを管理して、効率的で信頼性の高いネットワーク リクエスト機能を提供します。

おすすめ

転載: blog.csdn.net/weixin_47592544/article/details/131540648