3

C#/.NET 4 の Async メソッドに問題があります。w3wp プロセスにスレッドを追加しますが、スレッドを解放しません。サーバーは最終的に 400 前後のスレッド制限に達し、リサイクル中にアプリ プールにアクセスできなくなります。

ここで EndInvoke を間違って使用していませんか?

問題を再現する簡単な例を次に示します。

    [WebMethod]
    public void Test()
    {
        TestFind("test");
    }

    private delegate void TestFindDelegate(String val);
    private TestFindDelegate tfd;
    private IAsyncResult iar;

    public void TestFind(String val)
    {
        try
        {
            tfd = new TestFindDelegate(this.TestFindAsync);
            iar = tfd.BeginInvoke(val, null, null);
        }
        catch (Exception ex)
        {
            String msg = ex.Message;
        }
    }

    //Method runs asynchronously
    private void TestFindAsync(String val)
    {            
        try
        {
            //Run stuff here
        }
        catch (Exception ex)
        {
            String msg = ex.Message;
        }
        finally
        {
            tfd.EndInvoke(iar); //clean up resources
        }
    }

再現手順:
1. 上記のコードを Web service.asmx に追加し
ます。 2. タスク マネージャーを開き、スレッド列を追加し、プロセスを検索します
。 3. Fiddler を開き、Composer に移動して、Web サービスの URL/テストを入力します
。 4. [実行] をクリックします 20-40
5. プロセスのスレッド カウントが増加しているが、減少していないことを確認します。

4

1 に答える 1

2

EndInvoke問題は、適切に呼び出していない可能性があります。を使用するDelegate.BeginInvoke場合は、常に を呼び出す必要があり、メソッドが完了したEndInvokeに呼び出す必要があります。MSDNから:

どの手法を使用する場合でも、必ず EndInvoke を呼び出して非同期呼び出しを完了してください。

tfd現在、変数内のandを追跡iarしていますが、呼び出しごとにその変数が上書きされます。そのため、これをすばやく 100 回呼び出しても、呼び出すのは 1 回だけEndInvokeです。

より良いオプションは、Taskこれを実行するために使用することです:

public void TestFind(String val)
{
    Task.Factory.StartNew(() => this.TestFindAsync(val));
}

これはスレッドプールスレッドでこれを呼び出しますが、EndInvoke呼び出しやローカル変数を保存する必要はありません。

于 2013-06-12T23:05:49.913 に答える