あなたは暗黙のうちに2つの質問をしたので、両方に答えさせてください。
1. AppEngineインスタンスで複数の同時リクエストを処理するにはどうすればよいですか?
あなたは本当に2つのことをする必要があるだけです:
- フォルダーにあるファイルにステートメント
<threadsafe>true</threadsafe>
を追加します。appengine-web.xml
war\WEB-INF
- すべてのリクエストハンドラー内のコードが実際にスレッドセーフであることを確認してください。つまり
doGet(...)
、、などのメソッドでローカル変数のみを使用doPost(...)
するか、クラス変数またはグローバル変数へのすべてのアクセスを同期してください。
これにより、AppEngineインスタンスサーバーフレームワークに、コードがスレッドセーフであり、複数のリクエストを同時に処理するために、異なるスレッドですべてのリクエストハンドラーを複数回呼び出すことができるようになっていることが通知されます。注:AFAIK、これをサーブレットごとに設定することはできません。したがって、すべてのサーブレットはスレッドセーフである必要があります。
したがって、基本的に、投稿したエグゼキュータコードは、各AppEngineインスタンスのサーバーコードにすでに含まれており、実際には、doGet(...)
AppEngineがリクエストごとに作成(または再利用)する個別のスレッドのrunメソッド内からメソッドを呼び出します。基本的にdoGet()
すでにあなたですMyTask()
。
ドキュメントの関連部分はここにあります(実際にはあまり言及されていませんが):https ://developers.google.com/appengine/docs/java/config/appconfig#Using_Concurrent_Requests
2.投稿されたコードはこの(または他の)目的に役立ちますか?
現在の形式のAppEngineでは、独自のスレッドを作成して使用してリクエストを受け入れることはできません。これは、前述の方法を使用してハンドラー内にスレッドを作成することのみを許可しますが、この1つの要求に対して並列処理を実行することのみを許可し、2番目の要求を並列に受け入れないようにします(これは外部で発生します)。doGet(...)
currentRequestThreadFactory()
doGet()
名前currentRequestThreadFactory()
はここでは少し誤解を招く可能性があります。current
Factory
のRequestThreads
、つまりリクエストを処理するスレッドを返すという意味ではありません。これは、内にFactory
作成できるを返すことを意味します。したがって、残念ながら、現在の実行の範囲を超えて返されたThreadFactoryを使用することは実際には許可されていません。これは、それに基づいてエグゼキュータを作成し、クラス変数に保持することで提案されているようにです。Threads
currentRequest
doGet()
フロントエンドインスタンスの場合、呼び出し内で作成したスレッドは、メソッドが戻るdoGet()
とすぐに終了します。doGet()
バックエンドインスタンスの場合、実行を継続するスレッドを作成できますが、これらのスレッド内でリクエストを受け入れるためにサーバーソケットを開くことは許可されていないため、リクエスト処理を自分で管理することはできません。
appengineサーブレット内で実行できることと実行できないことの詳細については、次を参照してください。
Javaサーブレット環境-サンドボックス(具体的にはスレッドセクション)
完全を期すために、コードを「合法」にする方法を見てみましょう。
以下は機能するはずですが、コードが複数のリクエストを並行して処理できるという点では違いはありません。<threadsafe>true</threadsafe>
これは、appengine-web.xmlの設定によってのみ決定されます。したがって、技術的には、このコードは本当に非効率的であり、本質的に線形のプログラムフローを2つのスレッドに分割します。しかし、ここにとにかくあります:
public class MyServlet implements HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
ThreadFactory threadFactory = ThreadManager.currentRequestThreadFactory();
Executor executor = Executors.newCachedThreadPool(threadFactory);
Future<MyResult> result = executor.submit(new MyTask(request)); // Fires off request handling in a separate thread
writeResponse(response, result.get()); // Waits for thread to complete and builds response. After that, doGet() returns
}
}
現在処理しているリクエストに固有の別のスレッド内にすでにいるので、必ず「スレッド内のスレッド」を保存し、代わりにこれを行う必要があります。
public class MyServlet implements HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
writeResponse(response, new MyTask(request).call()); // Delegate request handling to MyTask object in current thread and write out returned response
}
}
または、さらに良いことに、コードをMyTask.call()からdoGet()メソッドに移動するだけです。;)
余談ですが、あなたが言及した10個の同時サーブレットスレッドの制限について:
これは(一時的な)設計上の決定であり、Googleがサーバーの負荷をより簡単に制御できるようにします(具体的にはサーブレットのメモリ使用量)。
これらの問題に関する詳細については、次を参照してください。
私は超リーンサーブレットコードを強く信じているので、このトピックも私を悩ませてきました。そのため、私の通常のサーブレットは、数千とは言わないまでも数百の同時リクエストを簡単に処理できます。インスタンスあたり10スレッドというこの恣意的な制限のために、より多くのインスタンスにお金を払わなければならないのは、控えめに言っても少し面倒です。しかし、私が上に投稿したリンクを読むと、彼らはこれを認識しており、より良い解決策に取り組んでいるようです。それでは、Google I /O2013が5月にどのような発表を行うか見てみましょう...:)