我正在尝试在Web worker中执行时提高脚本的性能。它旨在解析浏览器中的大型文本文件而不会崩溃。一切都运行良好,但我注意到使用Web worker时大文件的性能存在严重差异。
所以我进行了一个简单的实验。我在同一个输入上运行了两次脚本。第一次运行在页面的主线程中执行脚本(没有web worker)。当然,这会导致页面冻结并变得无法响应。对于第二次运行,我在Web worker中执行了脚本。
对于本实验中的小文件(< ~100 MB),性能差异可以忽略不计。但是,对于大型文件,解析在工作线程中需要大约20倍:
预计蓝线。它只需要大约11秒来解析文件,性能相当稳定:
红线是网络工作者内部的表现。这更令人惊讶:
前30秒的锯齿状线是正常的(jag是由解析文件的每个块后将结果发送到主线程的轻微延迟引起的)。但是,解析在30秒时相当突然减慢。 (请注意,我只使用一个Web工作者来完成工作;一次只能使用一个工作线程。)
我已确认在使用postMessage()
将结果发送到主线程时,延迟不。减速是在解析器的the tight loop中,这是完全同步的。由于我无法解释的原因,该循环显着减慢,并且在30秒后随着时间变慢。
但这只发生在网络工作者身上。正如您在上面看到的那样,在主线程中运行相同的代码,运行非常顺畅和快速。
为什么会这样?我该怎么做才能提高性能? (我不希望任何人完全理解该文件中的所有1,200多行代码。如果你这样做,那真是太棒了,但我觉得这与网络工作者的关系比我的代码更多,因为它在主文件中运行正常线程。)
系统:我在Mac OS 10.9.4上运行Chrome 35,内存为16 GB;四核2.7 GHz Intel Core i7,具有256 KB L2缓存(每个核心)和3 MB的L3缓存。文件块大小约为10 MB。
更新:刚刚在Firefox 30上尝试了它并且不在工作线程中遇到同样的减速(但在主线程中运行时它比Chrome慢) )。然而,尝试使用更大的文件(大约1 GB)进行相同的实验,在大约35-40秒之后(看起来)显着减速。
答案 0 :(得分:15)
Tyler Ault suggested one possibility on Google+结果非常有帮助。
他推测在工作线程中使用FileReaderSync
(而不是普通的'async FileReader
)并没有提供垃圾收集发生的机会。
将工作线程更改为异步使用FileReader
(这看起来像是一个性能步骤向后)将该过程加速回到37秒,就在我预期的那样
我还没有收到Tyler的回复,而且我不完全确定我理解为什么垃圾收集会成为罪魁祸首,但是关于FileReaderSync
的一些事情是彻底放慢了代码的速度
答案 1 :(得分:2)
你在运行什么硬件?您可能遇到CPU缓存抖动问题。例如,如果CPU高速缓存是每个核心1MB(仅作为示例)并且您开始尝试使用数据不断替换高速缓存(高速缓存未命中),那么您将遭受减速 - 这在MT系统中非常常见。这在IO传输中也很常见。此外,这些系统也倾向于为线程上下文提供一些OS开销。因此,如果产生大量线程,您可能花费更多时间来管理上下文而不是线程“正在工作”。我还没有查看你的代码,所以我可能会离开 - 但我的猜测是由于你的应用程序在做什么而在内存问题上。 :)
喔。怎么修。尝试使用与硬件匹配的小块单块执行块。最大限度地减少一次使用的线程数量 - 尽量将它们保持在硬件中核心数量的2-3倍(这实际上取决于您拥有的核心数量)。希望有所帮助。