如何使用Parallel.For / ForEach获得最大性能? (包括性能时间)
我正在尝试并行化我的Web解析工具,但速度增益似乎非常小。 我有i7-2600K(8核超线程)。
这里有一些代码可以向您展示这个想法。 我只展示了Parallel.ForEach
但你明白了:
List AllLinks = this.GetAllLinks(); ConcurrentDictionary AllTopics = new ConcurrentDictionary ( ); int count = 0; Stopwatch sw = new Stopwatch ( ); sw.Start ( ); Parallel.ForEach ( AllLinks, currentLink => { Topic topic = this.ExtractTopicData ( currentLink ); this.AllTopics.TryAdd ( currentLink, topic ); ++count; if ( count > 50 ) { Console.WriteLine ( sw.ElapsedMilliseconds ); count = 0; } } );
我得到这些时间:
Standard foreach loop: 24582 59234 82800 117786 140315 2 links per second Paralel.For: 21902 31649 41168 49817 59321 5 links per second Paralel.ForEach: 10217 20401 39056 49220 58125 5 links per second
首先,为什么Parallel.For
的“启动”时间要慢得多。
除此之外,并行循环比标准foreach循环提供2.5倍的速度。 这是正常的吗?
我可以设置一个设置,以便并行循环可以使用所有核心吗?
编辑:
这几乎是ExtractTopicData
作用:
HtmlAgilityPack.HtmlWeb web = new HtmlWeb ( ); HtmlAgilityPack.HtmlDocument doc = web.Load ( url ); IEnumerable links = doc.DocumentNode.SelectNodes ( "//*[@id="topicDetails"]" ); var topic = new Topic(); foreach ( var link in links ) { //parse the link data }
简要阅读HtmlAgilityPack.HtmlWeb
确认它正在使用同步WebRequest
API。 因此,您将长时间运行的任务放入ThreadPool(通过Parallel
)。 ThreadPool专为短期操作而设计,可以快速将线程返回池中。 阻止IO是一个很大的禁忌。 鉴于ThreadPool不愿意启动新线程(因为它不是为这种用法而设计的),你将受到这种行为的限制。
异步获取您的Web内容( 请参阅此处和此处以获取正确使用的API,您必须自己进一步调查… ),这样您就不会将 ThreadPool与阻塞任务捆绑在一起。 然后,您可以将解码后的响应提供给HtmlAgilityPack进行解析。
如果您真的想要提高性能,您还需要考虑WebRequest无法执行异步DNS查找。 IMO这是WebRequest设计中的一个可怕缺陷。
在此方法变为异步之前,BeginGetResponse方法需要完成一些同步设置任务(例如,DNS解析,代理检测和TCP套接字连接)。
它使高性能下载真正的PITA。 大约在这个时候,您可能会考虑编写自己的HTTP库,以便一切都可以在不阻塞的情况下执行(从而使ThreadPool匮乏)。
另外,在浏览网页时获得最大吞吐量是一件棘手的事情。 根据我的经验,您可以获得正确的代码,然后通过它必须经历的路由设备来解决。 许多国内路由器根本无法胜任工作。
上述就是C#学习教程:如何使用Parallel.For / ForEach获得最大性能? (包括性能时间)分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1045324.html