我正在制作C#软件来实现RFC 1951“ Deflate”压缩。选择块边界以最大程度地压缩时,可以并行计算两个备选块选择的大小,以提高性能(这是相当长的计算,涉及霍夫曼码的计算)。
这是非并行版本:
int bits2 = b2.GetBits();
int bits3 = b3.GetBits();
这是并行版本:
Task<int> t2 = Task<int>.Factory.StartNew( () => { return b2.GetBits(); } );
int bits3 = b3.GetBits(), bits2 = t2.Result;
但是并行版本实际上运行速度较慢,我不明白为什么。如果相关,处理器为Intel Core i7-6700HQ。完整的代码在这里:https://github.com/georgebarwood/pdf/blob/master/Deflator.cs
为什么并行版本运行速度较慢而不是更快,我是否犯了一个错误,并且有什么办法可以使并行版本运行得比非并行版本快?
答案 0 :(得分:2)
如果我在计算机上运行您的GetBits
方法,则该方法平均运行时间为3µs。并行运行代码会有一些开销。实际上,在调用者方对Task.Factory.StartNew
的调用也需要2到3 µs(我没有测量任务实际开始执行多长时间)。因此,在您的情况下,间接费用会抵消潜在收益。
这是使算法有效并行运行的困难之一:您需要确保工作单元足够大以抵消引起的开销。
答案 1 :(得分:1)
要回答我自己的问题“我能做些什么使并行版本比非并行版本运行得更快?”,我现在重新设计了代码以使用两个线程-第二个线程执行LZ77压缩-寻找输入的重复部分,将其编码为(匹配长度,距离)对,而主线程处理LZ77阶段的输出(生成霍夫曼代码,使用这些代码对输入进行编码)。
效果非常好,总体来说运行速度提高了约30%,这非常酷。
线程对我来说很新颖,我觉得代码有点吓人,我希望我的锁和内存屏障正确无误。看起来工作正常,但我认为很容易出现一个隐藏的并发错误,而该错误可能不会在测试中显示。
和以前一样,这里是代码的副本: https://github.com/georgebarwood/pdf/blob/master/Deflator.cs