c# – 如何在Thread-Local状态下使用Parallel.ForEach?

问题:我在一篇文章中看到了两个带有WebCLient的Parallel.Foreach()下载URL的实现.作者建议在第一个例子中,如果我们有一个100个网址的数组 – 将启动100个WebClient,其中大多数将超时.所以他提出了第二个实现,他使用了线程局部状态,他说“我们需要生成尽可能多的WebClient()对象”.

问题:第二个示例如何确保不会发生超时?或者换句话说,第二个例子如何考虑连接的局部限制?客户会被重复使用吗?

资源:

// First example
Parallel.ForEach(urls,
    (url,loopstate,index) =>
    {
        WebClient webclient = new WebClient();
        webclient.DownloadFile(url, filenames[index];
    });

// Second example
Parallel.ForEach(urls,
    () => new WebClient(),
    (url, loopstate, index, webclient) =>
       {
           webclient.DownloadFile(url, filenames[index]);
    },
    (webclient) => { });

注意:在多个线程上生成WebClient仅用于演示目的.我知道使用异步操作会更有效.

我得到源代码的链接(我简化了一下):When Should I Use Parallel.ForEach? When Should I Use PLINQ?查看“线程局部状态”一章.

最佳答案

in other words how the second example takes in consideration the
local limit of connections? Will the clients be reused or something?

第二个例子的作用是,不是每次迭代创建一个WebClient对象,而是每个线程创建一个WebClient.这意味着如果Parallel.ForEach使用4个线程,它将创建4个实例,并将在迭代之间重用这些对象.因此,能够重新使用由每个客户端创建的连接而不是新实例,而新实例又必须等待所有其他客户端连接关闭.

最终,所有客户端都在争夺通过底层ServicePointManager.DefaultConnectionLimit可用的相同IO资源.您打开的连接越少,每个请求完成执行的时间就越多.这也可以通过增加允许的连接限制数来解决,默认为2.

一般来说,不需要使用多个线程来执行并发IO请求.并行性实际上并没有帮助.

点赞