-->

并行I / O和重试逻辑用于错误处理(Parallel I/O and Retry Logic fo

2019-10-19 12:10发布

通常,并行处理是只与CPU密集型操作。 然而,特别PLINQ提供了使用WithDegreeOfParallelism扩展IO密集型的支持。 例如:

from site in new[]
{
    "www.albahari.com",
    "www.linqpad.net",
    "www.oreilly.com",
    "www.takeonit.com",
    "stackoverflow.com",
    "www.rebeccarey.com"  
}
.AsParallel().WithDegreeOfParallelism(6)
let p = new Ping().Send (site)
select new
{
    site,
    Result = p.Status,
    Time = p.RoundtripTime
}

但是,如果支持IO是WithDegreeOfParallelism的目标 ,怎能PLINQ进一步扩展或使用,实现了“重试”的效果,这是典型的IO操作的? 而关于“延迟”的效果呢?

例如,如果通过IO WCF服务调用抛出一个的CommunicationException,我可能要在移动到下一个资源之前,“3次尝试”战略再次提出同样的要求。 我可能还需要一分钟的等待时间之间的每个尝试。 而我“等”一分钟之间的每一个尝试,我不想阻塞,在等待的线程。

在这个MSDN文章的作者开始用类似于我上面显示的查询。 然后,他改造查询,以便没有线程阻塞。 不幸的是,他失去了在这个过程中WithDegreeOfParallelism。 而无论哪种方式,他并没有在发生错误时解决“重试”的问题。

任何人都有或知道这样做华而不实的方式吗?

我想制作一个允许值进行“重新插入”,同时收集是由PLINQ走到一个特殊的IEnumerable包装的。 这的确会造成“重试”的行为,但它仍然不会允许要求“之间重试延迟1分钟”。 我可以创建一个Thread.sleep()方法将延迟1分钟,但我尽量不阻塞线程。

思考?

Answer 1:

您的文章链接实际上展示了如何通过使用以避免IO绑定操作阻塞线程Task为基础的API( DownloadDataTask ),而不是:

然而,还是有一些关于这个代码是不理想的。 这项工作(发送关闭下载请求和阻塞),几乎不需要CPU,但它是由线程池线程,因为我使用的是默认的调度程序来完成。 理想情况下,线程应该只用于CPU绑定的工作(当实际有工做)。

使用PLINK / Task.Run / Task.Factory.StartNew用于基于IO的操作是一个反模式 。 PLINQ(相同Parallel.For等),有利于CPU密集型的计算工作,但是在分配和阻塞线程的自然异步网络/ IO绑定操作,这完全不同时,需要一个线程没有意义“飞行”。 跟随样本代码,你表明,这将是类似new Ping().SendAsync(site) ,返回Task 。 那么你可以做await Task.WhenAll(tasks)和过程中的错误。

请参阅“没有线程”由斯蒂芬·克利里,和他最近的回答应对并行IO的最大程度。 最重要的是,它很方便地将重试逻辑,没有得到任何涉及线程(例如,像这样 )。



文章来源: Parallel I/O and Retry Logic for Error Handling