编写在IIS上运行的服务。
基本上看起来像这样:
这似乎会创建另一个线程来调用ProcessRequest()。因此,我们仍然在<Access DB>上停滞不前,但这次我们使用的是不属于IIS的线程。对我而言,这很好看,保持了代码的简洁和易读性。
与同事交流时,他说这样做没有任何好处,因为线程仍然被阻塞。我同意,但反驳说它不是IIS线程,所以对我有好处。但是他声称,如果我们使用BeginProcessRequest()来确保只有<Access DB>是异步完成的,那么我们可以获得更多好处,因为没有线程会被阻塞。
以下是伪代码,因为我还没有解决细节问题:
如果这不会阻塞执行BeginExecuteNonQuery()的线程,那么我认为这是一种优势。但这需要底层实现使用select()来检测数据库调用是否有数据等待读取。虽然更容易实现的方法是只需暂停等待响应的线程(在这种情况下,添加额外的细粒度并没有给我带来任何好处)。
因此,有人有参考资料表明哪种方法实际上更好吗?或者对BeginExecuteNonQuery()的底层实现有什么说明?或者只是一些可能有帮助的一般信息。
谢谢!
编辑:
SqlConnection类包含一个线程池。
因此,当您在SqlCommand上执行BeginExecuteNonQuery()时,它实际上不需要创建线程。请求被发送,当从SQL Server返回数据时,主控线程将从池中旋转一个线程。因此,上述第3个选项不会浪费线程或在异步执行DB操作时导致线程挂起。
基本上看起来像这样:
void ProcessRequest(HttpContext context)
{
<Init Stuff>
<Access DB> // This may potentially stall for DB access
<Write Output to conext stream>
}
通过在<Access DB>部分阻塞线程,我们基本上是阻塞了其中一个IIS服务线程。因此,寻找解决方法的方式如下:
IAsyncResult BeginProcessRequest(HttpContext context,AsyncCallback cb,Object extraData)
{
this.del = new AsyncTaskDelegate(ProcessRequest);
this.del.BeginInvoke(context, cb, extraData);
}
void EndProcessRequest(IAsyncResult result)
{
this.del.EndInvoke(ar);
}
这似乎会创建另一个线程来调用ProcessRequest()。因此,我们仍然在<Access DB>上停滞不前,但这次我们使用的是不属于IIS的线程。对我而言,这很好看,保持了代码的简洁和易读性。
与同事交流时,他说这样做没有任何好处,因为线程仍然被阻塞。我同意,但反驳说它不是IIS线程,所以对我有好处。但是他声称,如果我们使用BeginProcessRequest()来确保只有<Access DB>是异步完成的,那么我们可以获得更多好处,因为没有线程会被阻塞。
以下是伪代码,因为我还没有解决细节问题:
void ProcessRequest(HttpContext context)
{ /* Do Nothing */ }
IAsyncResult BeginProcessRequest(HttpContext context,AsyncCallback cb,Object extraData)
{
<Init Stuff>
this.command = <Access DB>.getSQLCommand();
this.command.BeginExecuteNonQuery(cb,extraData); // Assume we want to wait for this to complete.
}
void EndProcessRequest(IAsyncResult result)
{
this.command.EndExecuteNonQuery(result);
<Write Output to conext stream>
}
如果这不会阻塞执行BeginExecuteNonQuery()的线程,那么我认为这是一种优势。但这需要底层实现使用select()来检测数据库调用是否有数据等待读取。虽然更容易实现的方法是只需暂停等待响应的线程(在这种情况下,添加额外的细粒度并没有给我带来任何好处)。
因此,有人有参考资料表明哪种方法实际上更好吗?或者对BeginExecuteNonQuery()的底层实现有什么说明?或者只是一些可能有帮助的一般信息。
谢谢!
编辑:
SqlConnection类包含一个线程池。
因此,当您在SqlCommand上执行BeginExecuteNonQuery()时,它实际上不需要创建线程。请求被发送,当从SQL Server返回数据时,主控线程将从池中旋转一个线程。因此,上述第3个选项不会浪费线程或在异步执行DB操作时导致线程挂起。
IHttpAsyncHandler
就没什么意义了。从BeginProcessRequest()
返回到调用cb
的时间段内,调用线程可以愉快地处理其他请求,然后调用EndProcessRequest()
进行清理。如果你只是在尝试减少与数据库相关站点的线程争用,那么 HTTP 超时可能是需要考虑的问题,但它们已经足够长了,在这种情况下,OP(或者他的同事)的方法非常完美。 - Simon Buchan