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