HttpWebRequest和I / O完成端口

时间:2011-01-24 07:24:41

标签: c# multithreading httpwebrequest threadpool io-completion-ports

我正在开发一个应用程序,它需要一种类型的消息才能访问数据库,而另一种类型的消息需要一些外部的xml api。

我必须处理A LOT ...其中一个重大挑战是让HttpWebRequest类表现良好。我最初开始只使用标准的同步方法和线程整个事情。这不好。

因此,经过一些阅读后,我看到推荐的方法是使用Begin / End方法将工作委托给IO完成端口,从而释放线程池并产生更好的性能。这似乎不是这样的......性能稍微好一些,但我当然看不到与threadpool相比使用的IO完成端口。

我有一个旋转的线程,并在线程池中向我发送可用的工作线程+完成端口。完成端口总是非常低(我看到最多使用9个)并且我总是使用大约120个工作线程(有时更多)。我对httpwebrequest中的所有方法使用了开始/结束模式:

Begin/EndGetRequestStream
Begin/EndWrite (Stream)
Begin/EndGetResponse
Begin/EndRead (Stream)

我做得对吗?我错过了什么吗?我可以同时使用(有时)多达2048个http连接(来自netstat输出) - 为什么完成端口号会这么低?

如果有人能就如何妥善处理这个管理工作线程,完成端口和httpwebrequest提出一些认真的建议,那将非常感激!

编辑:.NET是一个合理的工具吗?我可以使用.NET和System.Net堆栈获得大量的http连接吗?有人建议使用类似WinHttp(或其他一些C ++库)的东西,并从.NET中调用它,但这不是我特别想做的事情!

3 个答案:

答案 0 :(得分:6)

我理解它的方式,你没有占用I / O完成端口所有异步请求未完成的时间 - 它只是在返回数据时“忙”并且是正在相应的线程上处理。希望您在回调中没有非常做很多工作,这就是为什么您在任何时候都没有多个正在使用的端口。

实际上表现不佳?您的原因仅仅是数量较少?您是否获得了预期的吞吐量?

可能的一个问题是任何一台主机的HTTP连接池都相对较小。如果您对同一台计算机有数百个请求,那么默认情况下,一次只能实现实际的2个请求,以避免DoS攻击相关主机(并获得保留的好处 - 活)。您可以通过编程方式或使用app.config来增加此功能。当然,这可能不是您的问题,因为您已经解决了问题,或者因为您的所有请求都是针对不同的主机。 (如果netstat显示2048个连接,则听起来不错。)

答案 1 :(得分:0)

也许你的EndRead方法应该只将结果写入一个线程安全队列,然后从你控制下的少量工作线程读取。和/或使用HttpWebRequest在完成时发出可信对象的信号并编写自己的逻辑以等待来自单个(或少量)线程的所有未完成请求的事实。

答案 2 :(得分:0)

实际上只有9个完成端口线程意味着你可能正确有效地使用它们。我将假设你运行的机器有8个内核或4个超线程内核,这意味着操作系统将在任何时候尝试保持最多8个活动(不是休眠/阻塞/等待)完成端口线程。

如果其中一个正在运行的线程变为非活动状态(睡眠/阻止/等待)并且还有其他要处理的工作项,则会创建一个额外的线程以将活动计数保持为8.如果您看到9个线程,则表示您在完成端口线程上的方法中几乎没有阻塞,并且实际上在CPU上使用它们。

如果有8个线程主动在8个内核上进行CPU绑定工作,那么添加更多线程只会减慢速度(线程之间的上下文切换将是浪费的时间)。

您应该关注的是为什么您有120个其他线程以及它们正在做什么。