JavaEE Servlet 3.0から登場した非同期レスポンス startAsync() ですが、これがどういう役に立つのかいまひとつ理解できていません。
よくある例ではチャットアプリをCometで実現する、そのとき相手からの発言を待つコードをstartAsyncに渡す、なんていうのが解説されています。が、別にそんなことしなくても同期的にdoGetの中で相手からの発言を一定時間待つと言うコードを書くので同じことができるわけで。
startAsyncを使うと何かのリソースを節約できるのか? そういうことのような気もしますが、同期的にやっても非同期でやっても同じくスレッドが一本wait状態になるだけで、リソースの使用状況は同じに見えます。
startAsyncはどのような使い道のときに何を改善したくて導入されたものなのでしょうか。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ベストアンサー
コネクション毎にスレッドが必要だったのを、リクエスト毎にスレッドがあれば良いようにした認識です。
Asynchronous processing support in Servlet 3.0 | JavaWorld
にある、
When a connection is idle between requests, the thread can be recycled, and the connection is placed in a centralized NIO select set to detect new requests without consuming a separate thread.
の様に、selectを使う、所謂ノンブロッキングI/Oを使うことで、1スレッドで待ち受けて、リクエストがあった場合にスレッドを割り当てることが出来るようになったということかと思います。
結局裏でワーカースレッドが待機することになります。環境全体で待機しているスレッド数には(つまりコストには)変わりがないのでは? という主旨の質問になります。
については、待機するスレッドは1つなので、必要とするスレッド数は小さくなるということです。
仕様側には実装方法は書かれていないようですが、目的としては以下の部分かと思います。
サーブレット3.0仕様書邦訳版
2.3.3.3 非同期処理(Asynchronous processing)
時にはフィルタ及び/あるいはサーブレットが応答発生前にあるリソースあるいはイベントを待たない と、ある要求処理を終了できないことがある。例えば、あるサーブレットは応答を発生させる前に、 利用可能な JDBC 接続、リモートのウェブ・サービスからの応答、JMS メッセージ、あるいはアプリ ケーションのあるイベント、などを待つ必要がある。そのサーブレット内での待機は非効率な使い方 である。何故ならそれはスレッドと他の限られたリソースを消費するブロッキング動作であるからであ る。しばしばデータベースのような遅いリソースが多くのスレッドをアクセス待ちの状態でブロックさ せ、ウェブ・コンテナ全体のスレッドの枯渇とサービス品質劣化をもたらす。
サーブレット第 3 版では要求の非同期処理を導入しており、そのスレッドをコンテナに返して他のタ スクを実行できるようにしている。
(2016/07/07 15:30 追記)
上に書いた回答は不十分だったと思います。
(というより、仕様に書いてある以上のことを、私が勝手に期待した感じです。。)
AsyncContext.startAsync、AsyncContext.startするのは、目的としては
上記のサーブレット3.0仕様書の2.3.3.3 非同期処理のところにある通りのようですが、その効果は
「HTTP処理用のスレッドをつかみっぱなしにしないこと」の様です。
その結果として考えられるメリットは以下かと思います。
直接的なメリット(効果小)
HTTP処理用のスレッド数は通常なんらかの設定により上限があるため、
この制限とは別の管理のスレッドに処理が渡せることは、ある程度のメリットがあると思います。
とはいえ、実際の総スレッド数としては減るわけでもなくリソースの削減効果もないので、
大したメリットとは思えません。
間接的なメリット(効果大だが想定される使い方か不明)
こちらは、私の考える実装の可能性で、検証したわけでもどこかに書いてあったわけでもないですが、
処理が分離されることにより、ノンブロッキングI/Oを用いた通信を行うことによる
スレッド数の削減ができる前提が一つ満たされると思います。
例えば、指定した外部のWeb APIを呼び出して結果を取得する処理をノンブロッキングI/Oを用いて
複数のリクエストを1スレッドで同時に処理し、
結果が取れた場合のみにAsyncContext.startを呼び出して結果を返すようにできれば、
外部のWeb APIを呼び出して結果を待つ間は、複数のリクエストがあっても1スレッドしか使いません。
今までは、もしこうした処理を実装したとしても、HTTP処理用のスレッドで
処理を返さなければいけなかったので、使えませんでしたが、
AsyncContext.startAsyncの仕組みを使うことで、実装する余地は有るようになったと思います。
。
(2016/07/06 7:10追記)
上に記述した内容を補強する情報がありました。
Servlet 3.1でのノンブロッキングI/O対応
Servlet 3.1において、startAsyncをベースにして、リクエストやレスポンスのI/OをノンブロッキングI/OにするAPIが追加されています。
以下が仕様の追記部分の一部です。
Java Servlet Specification Version 3.1
3.7 Non Blocking IO
Non-blocking request processing in the Web Container helps improve the ever increasing demand for improved Web Container scalability, increase the number of connections that can simultaneously be handled by the Web Container. Non-blocking IO in the Servlet container allows developers to read data as it becomes available or write data when possible to do so. Non-blocking IO only works with async request processing in Servlets and Filters (as defined in Section 2.3.3.3, “Asynchronous processing” on page 2-10), and upgrade processing (as defined in Section 2.3.3.5, “Upgrade Processing” on page 2-20).
ノンブロッキングな外部サーバ呼び出しを行う例
以下のサイトで、ノンブロッキングな外部サーバ呼び出しを行うコード例がありました。こちらで動作確認はしてませんが、処理実装のイメージは、私のイメージ通りです。
lang
1protected void doGet(final HttpServletRequest req, HttpServletResponse resp) { 2 // Initialize async processing. 3 final AsyncContext context = req.startAsync(); 4 5 // This call does not block. 6 client.callExternalService( 7 // This callback is invoked after the external service responds. 8 new Callback<string>() { 9 public void callback(String result) { 10 ServletResponse response = context.getResponse(); 11 response.setContentType("text/plain"); 12 response.setCharacterEncoding("UTF-8"); 13 byte[] entity = ("Result: " + result + ".n").getBytes(Charset.forName("UTF-8")); 14 response.setContentLength(entity.length); 15 try { 16 response.getOutputStream().write(entity); 17 } catch (IOException e) { 18 // Ignored. 19 } 20 context.complete(); 21 } 22 }); 23}
投稿2016/07/07 01:17
編集2016/07/07 22:14総合スコア1546
0
解説する記事を見つけました。
中ほどに”非同期処理の実装”の記述が有ります。doGet()を抜けた後にresponseが返せる(doGetによるservlet待機のコストが減らせる)のがメリットなのかと思いました。
コンテンツ中に以下の記載が有ります。
非同期処理にするメリットは、サーブレットの実行に割り当てられているスレッドをコンテナがさっさと回収して、別のリクエストの処理に割り当てられて無駄が少なくなる、という点。
メモに書かれた通り、裏で実行・完了待ちしているスレッドが存在する点は変わりないと思います。非同期スレッドを実行させたままdoGetメソッドを終了させてコンテナにサーブレット実行リソースを回収出来るのであれば、非同期スレッドの処理時間に複数リクエストを受けるケースでリソースの利用が効率的になるのではないかと考えました。コンテナに開放出来るスレッドやリソースの種類など分からず、確証の有る回答にならず済みません。
投稿2016/07/07 00:35
編集2016/07/07 02:24総合スコア1339
0
startAsync()
ほほー、こんなことできるようになったんですね
最近、Javaは離れ気味なので追えてないなぁ・・・というのはいいとして
同期的にdoGetの中で相手からの発言を一定時間待つ
これ昔、(2000年頃)こういうのなんか名前ついてたなー、、、なんて言ったっけ?・・・
ってググってたら質問文にCometって書いてありましたね。
で、このComet、出てきた頃は、反則技だとか新しいWebだとかPushだとか色々言われてましたが、
しばらくしてすっかりきかなくなりましたねぇ。
まぁ同期的に待ってしまうと、いつまで待てばいいのとか、張りっぱなしじゃ
コネクションいくらあっても足りないじゃんとかそういうことから出てきたものだと思います。
時は流れて、ネットユーザーが爆発的に増えて、Twitterとかそんなのが出てきて
C1000k問題とかで、Node.jsがそれを解決だ!、、、みたいな流れで
遅ればせながらJavaEEも対応したのかなぁ・・・なんて思いますが。
全然頓珍漢だったらゴメンナサイ 老人の追憶です ^_^;
投稿2016/07/06 17:04
総合スコア2208
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/07 03:04
2016/07/07 04:59
2016/07/07 06:32
2016/07/07 14:17
2016/07/07 22:16
2016/07/07 22:58