问题:我在一篇文章中看到了两个带有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请求.并行性实际上并没有帮助.