并行库:对一个并行度进行延迟,将所有并行度延迟

本文关键字:延迟 并行度 一个 并行 | 更新日期: 2023-09-27 18:26:58

我有一个ConcurrentBag urls,它的项目正在并行处理(没有任何内容写回集合):

         urls.AsParallel<UrlInfo>().WithDegreeOfParallelism(17).ForAll( item =>
              UrlInfo info = MakeSynchronousWebRequest(item);
             (myProgress as IProgress<UrlInfo>).Report(info);
         });

我在网络请求中将超时设置为30秒。当遇到响应非常慢的url时,所有的并行处理都会停止。这是预期的行为,还是我应该在代码中查找一些问题?

进展如下:

        myProgress = new Progress<UrlInfo>( info =>
        {
            Action action = () =>
            {
                Interlocked.Increment(ref itested);
                if (info.status == UrlInfo.UrlStatusCode.dead)
                {
                    Interlocked.Increment(ref idead);
                    this.BadUrls.Add(info);
                }
                dead.Content = idead.ToString();
                tested.Content = itested.ToString();                    
            };
            try
            {
                Dispatcher.BeginInvoke(action);
            }
            catch (Exception ex)
            {
            }
        });

并行库:对一个并行度进行延迟,将所有并行度延迟

这是预期的行为。AsParallel直到所有操作完成才返回。由于您正在进行同步请求,您必须等到最慢的请求完成。然而,请注意,即使您有一个非常慢的任务占用了一个线程,调度器也会继续调度新任务,因为旧任务在剩余线程上完成。

这里有一个很有启发性的例子。它创建了101个任务。第一个任务占用一个线程5000毫秒,其他100个任务占用其余20个线程各1000毫秒。因此,它安排了其中20个任务,每个任务运行一秒钟,经过5次循环,完成所有100个任务,总共5000毫秒。然而,如果你把101改为102,这意味着你有101个任务在20个线程上翻腾,最终需要6000毫秒;直到5秒,第101个任务才有一个线程可以继续执行。如果你把101改为2,你会注意到它仍然需要5000毫秒,因为你必须等待缓慢的任务完成。

static void Main()
{
    ThreadPool.SetMinThreads(21, 21);
    var sw = new Stopwatch();
    sw.Start();
    Enumerable.Range(0, 101).AsParallel().WithDegreeOfParallelism(21).ForAll(i => Thread.Sleep(i==0?5000:1000));
    Console.WriteLine(sw.ElapsedMilliseconds);
}