我正在使用并行 linq,我正在尝试使用如下基本代码同时下载许多 url:
int threads = 10;
Dictionary<string, string> results = urls.AsParallel( threads ).ToDictionary( url => url, url => GetPage( url );
由于下载网页受网络限制而不是 CPU 限制,因此使用比我的处理器/内核数量更多的线程是非常有益的,因为每个线程的大部分时间都花在等待网络 catch 。然而,根据在我的双核机器上运行 threads = 2 与 threads = 10 具有相同性能的事实判断,我认为发送到 AsParallel 的线程数受限于核心数。
有什么方法可以覆盖这种行为吗?是否有没有此限制的类似库可用?
(我找到了这样一个 python 库,但需要在 .Net 中工作的东西)
最佳答案
这些 URL 是否指向同一台服务器?如果是这样,可能是您达到了 HTTP 连接限制而不是线程限制。有一种简单的方法可以判断 - 将您的代码更改为:
int threads = 10;
Dictionary<string, string> results = urls.AsParallel(threads)
.ToDictionary(url => url,
url => {
Console.WriteLine("On thread {0}",
Thread.CurrentThread.ManagedThreadId);
return GetPage(url);
});
编辑:嗯。我无法通过一些示例代码使 ToDictionary()
完全 并行化。它适用于 Select(url => GetPage(url))
但不适用于 ToDictionary
。将搜索一下。
编辑:好的,我仍然无法使 ToDictionary
并行化,但您可以解决这个问题。这是一个简短但完整的程序:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Linq.Parallel;
public class Test
{
static void Main()
{
var urls = Enumerable.Range(0, 100).Select(i => i.ToString());
int threads = 10;
Dictionary<string, string> results = urls.AsParallel(threads)
.Select(url => new { Url=url, Page=GetPage(url) })
.ToDictionary(x => x.Url, x => x.Page);
}
static string GetPage(string x)
{
Console.WriteLine("On thread {0} getting {1}",
Thread.CurrentThread.ManagedThreadId, x);
Thread.Sleep(2000);
return x;
}
}
那么,这使用了多少个线程? 5. 为什么?天知道。我有 2 个处理器,所以不是这样 - 我们指定了 10 个线程,所以不是这样。即使我更改 GetPage
以锤击 CPU,它仍然使用 5。
如果您只需要将它用于一项特定任务 - 并且您不介意稍微有点臭的代码 - 老实说,您最好自己实现它。
关于c# - Parallel Linq - 使用比处理器更多的线程(对于非 CPU 绑定(bind)任务),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/612253/