简体   繁体   English

设置ThreadPool.MaxThreads后从多个线程读取文件时出现WebException(超时)

[英]WebException (timeout) When Reading Files From Multiple Threads After Setting ThreadPool.MaxThreads

So, I tracked down the issue, but I don't understand the root cause and I'm curious. 因此,我找到了问题所在,但我不了解根本原因,我很好奇。

I have multiple threads reading files (sometimes the same file, but usually different files. This doesn't seem to matter) from a local drive. 我有多个线程从本地驱动器读取文件(有时是同一文件,但通常是不同的文件。这似乎无关紧要)。 This is the test setup, but in production these files are retrieved from a web server. 这是测试设置,但是在生产中,这些文件是从Web服务器检索的。

Anyway, I noticed that, after calling ThreadPool.SetMaxThreads() , I was receiving timeouts reading these files. 无论如何,我注意到在调用ThreadPool.SetMaxThreads() ,我收到读取这些文件的超时。 Removing that line makes the problem go away. 删除那条线可以解决问题。 My hunch is that it has to do with setting the number of asynchronous IO threads ( completionPortThreads , the second argument), but even when I set that value to a large number (50, 100, ...), the issue remains. 我的直觉是,这与设置异步IO线程的数量( completionPortThreads ,第二个参数)有关,但是即使我将该值设置为较大的值(50、100,...),问题仍然存在。

Removing the call to SetMaxThreads "fixes" the issue, though it means I can't increase or decrease the number of threads for testing purposes. 删除对SetMaxThreads的调用可以“解决”该问题,尽管这意味着我不能出于测试目的而增加或减少线程数。

Here is a block of code which reproduces the issue. 这是重现此问题的代码块。 The file size doesn't matter as my test files range anywhere from 2KB to 3MB. 文件大小无关紧要,因为我的测试文件范围从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;
        }
    }       
}

So, yeah, not sure what's going on here. 所以,是的,不知道这是怎么回事。 Even with a large value for IO threads I timeout on each test. 即使IO线程的值很大,我在每次测试中也会超时。 I'm certainly missing something. 我当然想念什么。

FileWebRequest which is the type returned by WebRequest.Create() also uses ThreadPool.QueueUserWorkItem. 由WebRequest.Create()返回的类型FileWebRequest也使用ThreadPool.QueueUserWorkItem。 Since you limit the worker threads, the queued work of FileWebRequest never gets executed. 由于限制了工作线程,因此FileWebRequest的排队工作永远不会执行。 You need to set max worker threads to at least _count + 1 (plus 1 so that there is at least one thread the can process the queued work by FileWebRequest). 您需要将最大工作线程数至少设置为_count + 1(加1,以便至少有一个线程可以通过FileWebRequest处理排队的工作)。

FileWebRequest.GetRequestStream does the following: FileWebRequest.GetRequestStream执行以下操作:

  1. ThreadPool.QueueUserWorkItem(read file) ThreadPool.QueueUserWorkItem(读取文件)
  2. Wait until the file is read or timeout is reached 等待直到读取文件或达到超时

Better Solution : Do not enqueue items to the ThreadPool. 更好的解决方案 :不要将项目排队到ThreadPool中。 Use WebRequest.GetResponseAsync instead. 请改用WebRequest.GetResponseAsync。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM