web-dev-qa-db-ja.com

Webアプリケーション内からの待機なしの非同期HttpWebRequest

私のWebアプリケーション(ASP.NET)には、HttpWebRequestを使用してRESTサービスを呼び出し、実行を続行するコードのブロックがあります。現在、完了したい時間よりも時間がかかっています。完全なWebリクエスト。RESTサービスが返すものは役に立たないということです。理想的には、非同期WebリクエストをRESTに送信したいと思います。サービスを提供し、応答を待たないでください。問題は、を使用して試してみたことです。

request.BeginGetResponse(New AsyncCallback(AddressOf myFunc), Nothing)

非同期リクエストを開始し、待機しない代わりに(非同期リクエストのデフォルトの動作であると思います)、BeginGetResponseの後の次のコード行を実行する前に、コールバック関数を継続的に実行します。

ASP.NETがWebアプリケーション内にある場合、それを同期要求に変換する可能性があると思われます。コールバック関数に渡されるIAsyncResult resultオブジェクトがあり、そのCompletedSynchronouslyプロパティを調べると、常にtrueに設定されているため、これを信じるようになりました。

ASP.NET Webアプリケーション内から非同期のHttpWebRequestを(待機なしで)実行できるかどうか、または常に同期要求に変換されるかどうかを誰かが知っていますか?

21
Adam

あなたはおそらく「ファイアアンドフォーゲット」パターンを見ているでしょう。ここにいくつかのリンクがあります。

http://weblogs.asp.net/albertpascual/archive/2009/05/14/fire-and-forget-class-for-asp-net.aspx

http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx

http://www.eggheadcafe.com/articles/20060727.asp

お役に立てれば

18
ram
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(myUrl);
//set up web request...
ThreadPool.QueueUserWorkItem(o=>{ myRequest.GetResponse(); });

ファイアアンドフォーゲットとも呼ばれます。

29

(注:コメントとして入力し始めましたが、調査中に知識を深めていくと、答えが出るほど大きくなりました)

1. ThreadPool.QueueUserWorkItem

@ramが提供する最初の2つのリンク、および@Bryan Batcheldersの回答は、物議を醸しているThreadPool.QueueUserWorkItemを利用しています。 @Perhentian link が示すように、不注意な使用はスレッドプールを枯渇させる可能性があるため、ASP.NETのコンテキスト内では物議を醸しています。

2.BeginInvoke

次に、BeginInvokeを利用する@ramの 番目のリンク を確認しました。本質的に、これはいくつかのコードに別のスレッドで実行も指示しているようです。したがって、ここでは解決策はありません。

3.BeginGetResponse

@Perhentiansに戻ります リンク 。 BeginGetResponseは、IO完了ポート(IOPC)を使用するため、実際のスレッドとは多少異なることを示しています。したがって、実際に探しているのは、余分なスレッドを作成せずにこれらのIOPCを使用するソリューションです。

さて、.NETがこれをどのように行うかを確認するために、私はHttpWebRequest.BeginGetResponseを掘り下げようとしました。これは、実際には内部呼び出しのぼろきれです。それは次のようになります:

  1. HttpWebRequest.BeginGetResponse
  2. ServicePoint.SubmitRequest
  3. Connection.SubmitRequest
  4. 2つのオプション:
    • 接続がクリアされている場合:Connection.StartRequest
    • それ以外の場合:Connection.WaitList.Add(request)

A.待機リスト

まず、オプション2について考えてみましょう。前のリクエストで接続が完了すると、前述のWaitListが処理されます。このチェーン全体に関係するConnectStreamを見ると、ThreadPool.QueueUserWorkItemと次のコメントが表示されます。

// otherwise we queue a work item to parse the chunk
// Consider: Will we have an issue of thread dying off
// if we make a IO Read from that thread???

したがって、少なくとも一部のフォールバックシナリオでは、BeginGetResponseを使用するだけで、スレッドがフレームワークによって誤って生成される可能性があります!

B. Connection.StartRequest

これで、接続が明確になるシナリオがまだあります。コールバックはSystem.Net.Sockets.Socket.BeginConnectによってインストールされ、実際にはBeginAcceptによって呼び出されます。さらに掘り下げると、結果が待機に使用されるThreadPool.UnsafeRegisterWaitForSingleObjectへの呼び出しが明らかになります。

結論

最後に、BeginGetResponseを実行するときに実際に何が起こっているかを知ることができます。

// 1. Connecting a socket
UnsafeNclNativeMethods.OSSOCK.WSAConnect(m_handle)

// 2. Registering the callback
m_RegisteredWait = ThreadPool.UnsafeRegisterWaitForSingleObject(m_AsyncEvent, s_RegisteredWaitCallback, this, Timeout.Infinite, true);

// 3. Waiting for the socket to complete
UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(m_handle, m_AsyncEvent.SafeWaitHandle, blockEventBits);

Timeout.Infiniteに注意してください。待機を実行しないコードパスをソケットで実行できるかどうかはまだ調査中ですが、今のところ、不可能に見えます。

私の結論として、ファイアアンドフォーゲットのシナリオでIOCPを使用する簡単な方法はないようです。したがって、BeginAcceptで完了を待たないように上記のソケットを取得できない限り、ThreadPoolで立ち往生しています。

13