1

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

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

我在 Web 请求中将超时设置为 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)
            {

            }

        });
4

1 回答 1

3

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

这是一个相当有启发性的例子。它创建了 101 个任务。第一个任务占用一个线程 5000 毫秒,其他 100 个任务在剩余的 20 个线程上运行 1000 毫秒。因此,它安排了其中的 20 个任务,每个任务运行一秒钟,通过该循环 5 次以完成所有 100 个任务,总共运行 5000 毫秒。但是,如果您将 101 更改为 102,则意味着您有 101 个任务在 20 个线程上运行,最终将花费 6000 毫秒;第 101 个任务在 5 秒标记之前没有线程可以处理。如果您将 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);
}
于 2013-08-09T17:58:32.350 回答