asp.net 将ThreadPool线程用于长时间运行的ADO.NET查询,这是可扩展的吗?

bgtovc5b  于 2023-05-23  发布在  .NET
关注(0)|答案(2)|浏览(113)

我们目前正在增强一个ASP.NET应用程序,该应用程序可以对许多产品执行报价。
目前,现有的报价引擎基本上是一个大的存储过程(每次调用2-3秒),后面是在过程调用后运行的少量业务逻辑。
我们正在研究对每个产品的多线程调用,以加快一组报价。
我们目前的方法是将每个产品报价工作封装在一个ThreadPool线程中。这似乎表现得更好,但我有点担心,尽管它在少量用户中表现良好,但它在生产环境中是否可以很好地扩展?
请注意,目前我们没有使用异步ADO.NET方法。
注意:我们调用ThreadPool的代码有一个对请求进行排队的节流器,因此我们一次只能使用ThreadPool中可配置数量的线程。我们也不需要等待报价结果出现在同一页面上,我们允许用户继续并检查更新(报价结果页面使用 AJAX 检查结果)。
进一步说明:首选的解决方案是使用消息队列,因为报价服务是单向操作。然而,项目的时间表并没有给我们提供时间来做这件事。
与此同时,我们将修改实现以使用ADO.NET的异步方法(因为这是进程的所有长时间运行的方面),从而节省了使用ThreadPool线程的需要。

wooyq4lh

wooyq4lh1#

将ThreadPool线程用于长时间运行的ADO.NET查询。这是可扩展的吗?
简短的回答是否定的,它是不可扩展的。
原因是ThreadPool线程还用于处理常规ASP.NET请求(BeginInvoke也是如此)。这些线程的数量是有限的,当它们用完时,传入的HTTP请求将阻塞,直到有线程可用。
尽管可以增加ASP.NET线程池中的线程数,但仍存在其他问题,例如线程数不是固定的;它响应于负载而缓慢增加。您可以/应该使用异步页面,但这仍然留下了如何实际运行SP的问题。如果可以的话,最好切换到异步ADO.NET方法。它们也比每个请求使用一个线程更轻量级。
如果有帮助的话,我在我的书(Ultra-Fast ASP.NET)中详细介绍了这个主题。

vuktfyat

vuktfyat2#

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();
}

相关问题