OkHttp ライブラリを使用していくつかのパフォーマンステストを行ったところ、すばらしいことがわかりました。 http://httpbin.org/delay/1 への80件のリクエストを実行しました。これにより、私のHTC One電話で4.7秒に、リクエストごとに1秒ずつ意図的に一時停止します。私はコードを見て、なぜそれがとても速いのかを見つけようとしています。開発者(Square Inc)は、接続プーリングと非同期呼び出しを宣伝しています。どちらも優れたパフォーマンスに貢献していると思います。
私は.NETの世界から来ており、.NET 4.5では、非同期 GetResponse-method を備えた真の非同期HTTPライブラリがあります。応答を待つ間にOSにスレッドを譲ることにより、リソースを解放して、より多くのHTTPリクエストなどを開始できます。問題は、OkHttp(またはAndroidのその他のHTTPライブラリ)で同じパターンを見ることができないことです。したがって、80秒の1秒のリクエストを4秒で実行するにはどうすればよいでしょうか。 ?スレッドベースではありませんよね?80(または20)スレッドを起動していませんか?
具体的には、 com.squareup.okhttp.Call.beginRequest() で、sendRequest
とgetResponse
の呼び出しの間にスレッドが生成されないことがわかります。
if (canceled) return null;
try {
engine.sendRequest();
if (request.body() != null) {
BufferedSink sink = engine.getBufferedRequestBody();
request.body().writeTo(sink);
}
engine.readResponse();
} catch (IOException e) {
HttpEngine retryEngine = engine.recover(e, null);
if (retryEngine != null) {
engine = retryEngine;
continue;
}
// Give up; recovery is not possible.
throw e;
}
Response response = engine.getResponse();
では、80の "並列"呼び出しをどのようにして可能にするのでしょうか。
ライブラリを使用するためにこれを知る必要はありませんが、非同期プログラミングに興味があり、OkHttp/SquareIncがどのように動作するかを本当に理解したいこれを解決しました。
OkHttpソースをプロジェクトにリンクし、ロギングをコアリクエストクラスであるCall.Javaに挿入することで、いくつかのテストを行いました。私が見つけたのは、OkHttpが実際に各呼び出しにスレッドを使用し、誤って想定したように応答を待機している間にnotしないことです。たとえばVolleyよりも高速である唯一の理由は、OkHttpがInteger.MAX_VALUE
(Dipatcher.Java
行58)を使用しているのに対して、Volleyはスレッド制限を4にハードコーディングしているためです。
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
以下は、80件のリクエストを「非同期に」キューに入れて実行したときのLogCatログの抜粋です。
05-31 12:15:23.884 27989-28025/nilzor.okhttp I/OKH﹕ Starting request 1
05-31 12:15:23.884 27989-28026/nilzor.okhttp I/OKH﹕ Starting request 2
05-31 12:15:24.044 27989-28199/nilzor.okhttp I/OKH﹕ Starting request 79
05-31 12:15:24.054 27989-28202/nilzor.okhttp I/OKH﹕ Starting request 80
05-31 12:15:25.324 27989-28025/nilzor.okhttp I/OKH﹕ Getting response 1 after 1436ms
05-31 12:15:26.374 27989-28026/nilzor.okhttp I/OKH﹕ Getting response 2 after 2451ms
05-31 12:15:27.334 27989-28199/nilzor.okhttp I/OKH﹕ Getting response 79 after 3289ms
05-31 12:15:26.354 27989-28202/nilzor.okhttp I/OKH﹕ Getting response 80 after 2305ms
形式xxxxx-yyyyy
の3番目の列は、プロセスID(x)とスレッドID(y)を示します。各リクエストが独自のスレッドを取得する方法と、同じスレッドが応答を処理する方法に注意してください。 完全ログ 。これは、応答の待機中に80のブロッキングスレッドがあることを意味します。これは、true非同期プログラミングを行う方法ではありません。
OkHttp/Square Incの防御では、真のエンドツーエンドの非同期HTTP通信があるとは決して主張せず、消費者に非同期インターフェースを提供するだけです。それは結構です。そしてそれはまたよく機能し、他の多くのことを行います。これは良いライブラリですが、真の非同期HTTP通信があると誤解しました。
それ以来、私が探しているものを見つけるためにキーワード「NIO」を探すことを理解しました。 AndroidAsync や Ion のようなライブラリは有望なようです。
現在、OkHttpは非同期ソケットを使用していません。 enqueue()
で非同期APIを使用している場合、Dispatcher
は複数のスレッドを起動し、複数の同時リクエストを作成します。すべてのリクエストに同じOkHttp
クライアントを使用すると、ホストごとに5つの接続に制限されます。