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 具有内置的异步处理程序,可让您启动请求,它在非处理程序线程上运行,并且可以在所有内置的第三个线程(不同于原始请求处理程序线程)上完成。我已经用过很多次了。

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 回答