0

所以,我追查了这个问题,但我不明白根本原因,我很好奇。

我有多个线程从本地驱动器读取文件(有时是同一个文件,但通常是不同的文件。这似乎无关紧要)。这是测试设置,但在生产中,这些文件是从 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 线程的值很大,我也会在每次测试中超时。我当然错过了一些东西。

4

1 回答 1

1

WebRequest.Create() 返回的类型 FileWebRequest 也使用 ThreadPool.QueueUserWorkItem。由于您限制了工作线程,因此 FileWebRequest 的排队工作永远不会被执行。您需要将最大工作线程数设置为至少 _count + 1(加 1,以便至少有一个线程可以处理 FileWebRequest 排队的工作)。

FileWebRequest.GetRequestStream 执行以下操作:

  1. ThreadPool.QueueUserWorkItem(读取文件)
  2. 等到文件被读取或达到超时

更好的解决方案:不要将项目排入线程池。请改用 WebRequest.GetResponseAsync。

于 2013-11-13T01:47:38.983 回答