所以,我追查了这个问题,但我不明白根本原因而且我很好奇。
我有多个线程从本地驱动器读取文件(有时是相同的文件,但通常是不同的文件。这似乎并不重要)。这是测试设置,但在生产中,这些文件是从Web服务器检索的。
无论如何,我注意到,在致电ThreadPool.SetMaxThreads()
之后,我收到了读取这些文件的超时。删除该行会使问题消失。我的预感是它与设置异步IO线程的数量(completionPortThreads
,第二个参数)有关,但即使我将该值设置为较大的数字(50,100,...),问题仍然存在
删除对SetMaxThreads
的调用“修复了”问题,但这意味着我无法增加或减少用于测试目的的线程数。
这是一段重现问题的代码。文件大小无关紧要,因为我的测试文件范围从2KB到3MB不等。
class Program
{
static void Main(string[] args)
{
_count = 15;
// Comment this line out and everything works
ThreadPool.SetMaxThreads(13, 50);
using (var mre = new ManualResetEvent(false))
{
for (int i = 0; i < _count; ++i)
{
ThreadPool.QueueUserWorkItem(ThreadFunc, mre);
}
mre.WaitOne();
}
}
private static readonly ConcurrentStack<byte[]> _files = new ConcurrentStack<byte[]>();
private static int _count;
private static void ThreadFunc(object o)
{
const string path = @"SomeLocalFile";
var file = ReadFile(path);
_files.Push(file);
if (Interlocked.Decrement(ref _count) == 0)
{
((ManualResetEvent)o).Set();
}
}
private static byte[] ReadFile(string uri)
{
var request = WebRequest.Create(uri);
using (var response = request.GetResponse())
using (var stream = response.GetResponseStream())
{
var ret = new byte[stream.Length];
stream.Read(ret, 0, ret.Length);
return ret;
}
}
}
所以,是的,不知道这里发生了什么。即使IO线程值很大,我也会在每次测试时超时。我当然错过了一些东西。
答案 0 :(得分:1)
FileWebRequest是WebRequest.Create()返回的类型,它也使用ThreadPool.QueueUserWorkItem。由于您限制了工作线程,因此FileWebRequest的排队工作永远不会被执行。您需要将max worker threads设置为至少_count + 1(加1,以便至少有一个线程可以处理FileWebRequest排队的工作)。
FileWebRequest.GetRequestStream执行以下操作:
更好的解决方案: 不要将项目排入ThreadPool。改为使用WebRequest.GetResponseAsync。