C# 并行库:一个并行度上的延迟是否会延迟所有并行度?

C# 并行库:一个并行度上的延迟是否会延迟所有并行度?,c#,task-parallel-library,C#,Task Parallel Library,我有一个ConcurrentBagURL,其项目正在并行处理(没有任何内容被写回集合): url.aspallel().WithDegreeOfParallelism(17).ForAll(item=> UrlInfo info=MakeSynchronousWebRequest(项目); 报告(信息); }); 我在web请求中将超时设置为30秒。当遇到响应速度非常慢的url时,所有并行处理都会停止。这是预期的行为,还是我应该在代码中查找一些问题 进展如下: myProgre

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

url.aspallel().WithDegreeOfParallelism(17).ForAll(item=>
UrlInfo info=MakeSynchronousWebRequest(项目);
报告(信息);
});
我在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)
            {

            }

        });
myProgress=新进度(info=>
{
动作动作=()=>
{
联锁增量(参考测试);
if(info.status==UrlInfo.UrlStatusCode.dead)
{
联锁增量(参考idead);
this.BadUrls.Add(info);
}
dead.Content=idead.ToString();
tested.Content=itested.ToString();
};
尝试
{
调度员。开始激活(操作);
}
捕获(例外情况除外)
{
}
});

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

这里有一个很有启发性的例子。它创建了101个任务。第一个任务占用一个线程5000毫秒,其他100个任务占用其余20个线程1000毫秒。所以它安排了20个任务,每个任务运行1秒,通过5次循环完成所有100个任务,总共5000毫秒。但是,如果将101更改为102,这意味着在20个线程上有101个任务在运行,这将需要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);
}

这应该是异步的。我还没有能够让AsParel处理异步web请求并将进度报告回UI。你是说我看到的行为是预期的吗?使用
await Task.whalll(url.AsParallel().Select(async item=>{await…}))
如果你只有一个异步操作,你可以直接返回它的
Task
,而不是使lambda异步。注意,你应该只调用
AsParallel()
如果存在要并行化的重要同步步骤。如果所有的工作都是异步的,那么就不需要线程。非常有启发性,谢谢。但我仍然不完全清楚是什么条件导致了进展被公布,因为我不清楚“行动”到底是什么。在单个线程上运行到完成的单个任务?在为并行化分配的所有线程上运行到完成的单个任务?进度正在更新我的UI,但进度更新暂停,然后重新开始。并不是说在进行进度更新之前必须处理枚举中的每一项。@Tim进度代码是什么样子的?有几种方法可以做到这一点。@Tim您是否从UI线程启动
URL.aspallel()…
块?如果是这样,那么UI线程也将用于一些并行块,这显然会降低响应速度。尝试从新线程启动它,所有块都将在线程池中运行,让您的UI线程可以自由进行更新。@Tim请参阅此处的最后一节:感谢链接。但这并不像链接所暗示的那么简单。当我使用task.Factory.StartNew()将并行任务包装到一个新任务中时,我在mscorlib.dll中得到一个InvalidOperationException,它没有被我的
catch(AggregateException aex)
块捕获在并行循环中,因此我甚至不确定问题发生在哪里。
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);
}