2

現在、多数の製品の見積もりを実行するASP.NETアプリを拡張しています。

現在、既存の見積もりエンジンは基本的に大きなストアドプロシージャ(呼び出しごとに2〜3秒)であり、その後にプロシージャ呼び出しの後に実行される少量のビジネスロジックが続きます。

一連の見積もりをスピードアップするために、各製品への呼び出しをマルチスレッド化することを検討しています。

現在のアプローチは、各製品見積もり作業をThreadPoolスレッドにカプセル化することです。これはパフォーマンスがはるかに優れているように見えますが、少数のユーザーでうまく機能しているにもかかわらず、本番環境でうまく拡張できるかどうか少し心配しています。

現在、非同期ADO.NETメソッドを使用していないことに注意してください。

注:ThreadPoolを呼び出すコードには、リクエストをキューに入れるスロットルがあるため、一度にThreadPoolから構成可能な量のスレッドのみを使用できます。また、同じページで見積もり結果を待つ必要はありません。ユーザーが進行して更新を確認できるようにします(見積もり結果ページはAJAXを使用して結果を確認します)。

さらに注意:見積もりサービスは一方向の操作であるため、推奨される解決策はメッセージキューを使用することです。しかし、プロジェクトのタイムスケールでは、これを行う時間がありませんでした。

それまでの間、ADO.NETの非同期メソッドを使用するように実装を修正します(プロセスの長期的な側面がすべてここにあるため)。ThreadPoolスレッドを使用する必要がなくなります。

4

2 に答える 2

6

長時間実行されるADO.NETクエリでThreadPoolスレッドを使用する。これはスケーラブルですか?

簡単な答えはノーです。スケーラブルではありません。

その理由は、ThreadPoolスレッドは通常のASP.NET要求の処理にも使用されるためです(BeginInvokeについても同じことが言えます)。これらのスレッドの数には限りがあり、それらが使い果たされると、着信HTTPリクエストはスレッドが使用可能になるまでブロックされます。

ASP.NETスレッドプール内のスレッドの数を増やすことはできますが、スレッドの数が固定されていないなど、他の問題があります。負荷に応じてゆっくりと増加します。非同期ページを使用できます/使用する必要がありますが、それでも実際にSPを実行する方法については疑問が残ります。可能であれば、その部分を非同期ADO.NETメソッドに切り替えることをお勧めします。また、リクエストごとにスレッドを使用するよりもはるかに軽量です。

それが役立つ場合は、この主題について私の本(Ultra-Fast ASP.NET)で詳しく説明します。

于 2009-11-18T06:10:07.280 に答える
1

ASP.NETには、要求を開始できる非同期ハンドラーが組み込まれています。これは、非ハンドラースレッドで実行され、すべて組み込みの3番目のスレッド(元の要求ハンドラースレッドとは異なります)で完了する場合があります。私はそれを何度も使用しました。

http://msdn.microsoft.com/en-us/magazine/cc163725.aspx

それをすべて接続するための小さなヘルパーメソッドを自分で作成します。

/// <summary>
/// On load event override
/// </summary>
/// <param name="e">arguments to the event</param>
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    string query = this.Page.Request.QueryString["query"];
    if (!string.IsNullOrEmpty(query))
    {
        var pat = new PageAsyncTask(this.BeginAsync, this.EndAsync, this.TimeOut, query);
        this.Page.RegisterAsyncTask(pat);
    }
    string me = string.Format(Format, System.Threading.Thread.CurrentThread.ManagedThreadId, "Onload");
    Trace.Write(me);
}
protected override void Render(HtmlTextWriter writer)
{
    string me = string.Format(Format, System.Threading.Thread.CurrentThread.ManagedThreadId, "Render");
    Trace.Write(me);
    this.Icompleted.Text = DateTime.Now.ToString();
    base.Render(writer);
}
/// <summary>
/// start the async task
/// </summary>
/// <param name="sender">original caller</param>
/// <param name="e">unused arguments</param>
/// <param name="cb">call back routine</param>
/// <param name="state">saved stated</param>
/// <returns>IAsyncResult to signal ender</returns>
private IAsyncResult BeginAsync(object sender, EventArgs e, AsyncCallback cb, object state)
{
    this.bsc = new YourWebServiceReferenceGoesHere();
    return this.bsc.BeginGetResponseXml("1", (string)state, "10", "1", cb, state);
}

/// <summary>
/// when the task completes
/// </summary>
/// <param name="ar">the async result</param>
private void EndAsync(IAsyncResult ar)
{
    XmlResponse response = this.bsc.EndGetResponseXml(ar);
    this.bsc.Close();
    this.bsc = null;
    this.PostProcess(response);
}

private void TimeOut(IAsyncResult ar)
{
    // currently we do nothing here.
}

/// <summary>
/// 
/// </summary>
private void PostProcess(XmlResponse response )
{
    string me = string.Format(Format, System.Threading.Thread.CurrentThread.ManagedThreadId, "bingsearch");
    Trace.Write(me);
    var xds = new XmlDataSource 
    { 
        EnableCaching = false, 
        CacheDuration = 0, 
        Data = response.Xml, 
        Transform = this.RemoveNamespaces() 
    };
    this.some.DataSource = xds;
    this.some.DataBind();
}
于 2009-11-18T06:16:06.587 に答える