.net 并行ForEach太慢了
我想再做一只蜘蛛。为此,我决定继续执行任务。我创造了一点概念证明。它是有效的,但我认为,它有点慢.net 并行ForEach太慢了,.net,task-parallel-library,task,.net,Task Parallel Library,Task,我想再做一只蜘蛛。为此,我决定继续执行任务。我创造了一点概念证明。它是有效的,但我认为,它有点慢 class Program { static void Main(string[] args) { InitializeUrls(); Start(); Console.ReadKey(); } private static void InitializeUrls() { _random
class Program
{
static void Main(string[] args)
{
InitializeUrls();
Start();
Console.ReadKey();
}
private static void InitializeUrls()
{
_random = new Random();
List<int> numbers = Enumerable.Range(0, 100).ToList();
foreach (int number in numbers)
_urls.Add(number.ToString());
}
private static readonly BlockingCollection<string> _urls = new BlockingCollection<string>();
private static readonly TaskFactory _factory = new TaskFactory();
private static CancellationTokenSource _tokenSource;
private static Task _task;
private static Random _random;
public static void Start()
{
_tokenSource = new CancellationTokenSource();
_task = _factory.StartNew(
() =>
{
try
{
Parallel.ForEach(
_urls.GetConsumingEnumerable(),
new ParallelOptions
{
MaxDegreeOfParallelism = 100, //number of threads running parallel
CancellationToken = _tokenSource.Token
},
(url, loopState) =>
{
if (!_tokenSource.IsCancellationRequested)
{
//here is the action
int waitTime = 5;// _random.Next(0, 15);
Console.WriteLine(string.Format("url {0}\ttime {1}\tthreadID {2}", url, waitTime,Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(waitTime * 1000);
}
else
{
//stop
loopState.Stop();
}
});
}
catch (OperationCanceledException exception)
{
Console.WriteLine("Error when ending the operation", exception.ToString());
}
catch (Exception exception)
{
Console.WriteLine("General exception", exception);
}
},
_tokenSource.Token);
}
}
类程序
{
静态void Main(字符串[]参数)
{
初始化eurls();
Start();
Console.ReadKey();
}
私有静态无效初始值设定项EURLS()
{
_随机=新随机();
列表编号=可枚举的.Range(01100).ToList();
foreach(整数中的整数)
_Add(number.ToString());
}
私有静态只读BlockingCollection _URL=new BlockingCollection();
私有静态只读TaskFactory _factory=new TaskFactory();
私有静态CancellationTokenSource\u tokenSource;
私有静态任务_任务;
私有静态随机(u Random),;
公共静态void Start()
{
_tokenSource=新的CancellationTokenSource();
_任务=_factory.StartNew(
() =>
{
尝试
{
并行ForEach(
_url.getConsuminegumerable(),
新的并行选项
{
MaxDegreeOfParallelism=100,//并行运行的线程数
CancellationToken=\u tokenSource.Token
},
(url,loopState)=>
{
如果(!\u tokenSource.IsCancellationRequested)
{
//这就是行动
int waitTime=5;//_random.Next(0,15);
WriteLine(string.Format(“url{0}\ttime{1}\tthreadID{2}”、url、waitTime、Thread.CurrentThread.ManagedThreadId));
线程睡眠(等待时间*1000);
}
其他的
{
//停止
loopState.Stop();
}
});
}
捕获(操作取消异常异常)
{
Console.WriteLine(“结束操作时出错”,exception.ToString());
}
捕获(异常)
{
Console.WriteLine(“一般异常”,异常);
}
},
_tokenSource.Token);
}
}
如您所见,我可以设置一次运行的线程数。当我将其设置为1时,效果很好,它将url写入控制台并等待5秒钟。
当我将它设置为100时,我希望它能立即创建100个任务,但如果您运行它,它不会。它获取URL的速度非常慢。你知道为什么会发生这种情况吗?如果你的工作是CPU受限的,那么添加比内核更多的线程不会有任何好处 如果您的工作不受CPU限制(例如,睡眠),则应使用异步(
await Task.WhenAll(stuff.Select(async s=>await…)
),这样您就不需要任何线程
当我将其设置为100时,我希望它能够创建100个任务
立即
这是你的错误。您设置的变量不是“DegreeOfParallelism”,而是“MaxDegreeOfParallelism”。Parallel.ForEach
将以少量任务开始,然后随着工作的完成逐渐增加到您定义的最大值
我非常推荐你阅读微软的免费电子书。它讨论了类似于Parallel.ForEach
等的行为
如果你想立即得到100个线程,你只需要使用一个普通的ForEach并自己排队工作。您需要某种速率限制器来限制最大并行度
var degreeOfParallelism = new Semaphore(100, 100);
foreach(var loopUrl in _urls.GetConsumingEnumerable())
{
//If you are on C# 5 this line is not necessary.
var url = loopUrl;
if (_tokenSource.IsCancellationRequested)
{
//Stop
break;
}
//Takes one slot up in the pool of 100.
degreeOfParallelism.WaitOne();
ThreadPool.QueueUserWorkItem((state) =>
{
try
{
//here is the action
int waitTime = 5;// _random.Next(0, 15);
Console.WriteLine(string.Format("url {0}\ttime {1}\tthreadID {2}", url, waitTime,Thread.CurrentThread.ManagedThreadId));
Thread.Sleep(waitTime * 1000);
}
finally
{
//Release a item back to the pool.
degreeOfParallelism.Release();
}
});
}
然而,如果你正在做一个网络爬虫并且在.NET4.5上,你应该根本不需要使用线程。相反,使用函数的
xxxxxancy()
版本,您可以保留100个任务的列表,只需执行Task.whany(您的任务列表)
即可检测一个任务何时完成。实际上,您不会运行100个单独的线程。这里有一个指向另一个堆栈溢出问题的链接,这个问题与相同的事情有关:好的,我理解为什么这只限于我拥有的内核数(4)。但是我想我可以有任意多个线程并行运行。我很确定我已经看到很多任务都是在做其他事情。为什么这种构造不同?据我所知,可以有尽可能多的“任务”排队,但它仍然与CPU可以处理的线程数有关。我个人没有资格详细解释,但是有很多关于网络上并行计算的信息和理论。祝你好运