我正在使用一个与数组一起工作的C#应用程序。它遍历它(意味着一次只使用数组的一个狭窄部分)。我正在考虑在其中添加线程以使其更快地执行(它在双核计算机上运行)。问题是我不知道它是否真的会有所帮助,因为线程需要花费一些成本,这个成本很可能比并行增益更多......那么我如何确定线程是否会有所帮助呢?
答案 0 :(得分:7)
尝试编写一些基准测试,尽可能地模拟实际使用软件的实际情况。
测试并计算单线程版本。测试和计算多线程版本。比较两组结果。
答案 1 :(得分:4)
如果您的应用程序受CPU限制(即它没有花时间尝试读取文件或等待来自设备的数据)并且几乎没有共享实时数据(数据被更改,如果它只读它的罚款在线程之间,你可以通过添加另一个线程(只要它仍然保持CPU绑定)几乎将速度提高50-> 75%。
多线程的主要开销来自2个位置。
创作&初始化线程。创建一个线程需要分配相当多的资源,并涉及内核和用户模式之间的交换,虽然每个线程一次性,但这很昂贵,所以如果线程在任何合理的时间内运行,你几乎可以忽略它。缓解此问题的最佳方法是使用线程池,因为它将保留线程并且不需要重新创建。
处理数据同步。如果一个线程正在从另一个正在写入的数据中读取,那么通常会发生坏事(如果两者都在改变它,则会更糟)。这要求您在更改数据之前锁定数据,以便没有线程读取半值。这些锁通常也很慢。要缓解此问题,您需要设计数据布局,以便线程不需要尽可能多地读取或写入相同的数据。如果你确实需要很多这些锁,那么它可能比单线程选项慢。
简而言之,如果你正在做一些需要CPU分享大量数据的东西,那么多线程它将会更慢,如果程序没有CPU限制,那么几乎没有差别(可能是很慢,取决于它绑定的内容,例如CD /硬盘驱动器)。如果您的程序符合这些条件,那么可能值得添加另一个线程(尽管唯一可以确定的方法是分析)。
还有一点需要注意的是,您应该只创建与物理内核一样多的CPU绑定线程(大多数时候处于空闲状态的线程,例如GUI消息泵线程,在这种情况下可以忽略)。
P.S。您可以通过使用称为“无锁编程”的方法来降低锁定数据的成本,尽管这种方法实际上只应由具有丰富多线程经验并清楚了解其目标体系结构的人员(包括如何处理缓存和内存总线)。
答案 2 :(得分:1)
我同意Luke's answer。对它进行基准测试,这是确定的唯一方法。
我还可以预测结果 - 当线程数与核心数匹配时最快的版本,如果数组非常小并且每个线程只需要处理几个项目,则设置为EXCEPT /拆解时间可能比处理本身大。有多少 - 这取决于你做了什么。再次 - 基准。
我建议找出“线程有用的最小项目数”。然后,当您决定生成多少个线程(或从池中获取)时,请检查计算机具有多少个核心以及有多少个项目。尽可能多地生成线程,但只有计算机具有核心,而不是每个线程的数量都少于要处理的最小项目数。
例如,如果最小项目数是1000,那么;计算机有4个核心;并且你的列表包含2500个项目,你只会生成2个线程,因为更多的线程效率低下(每个线程处理的项目少于1000个)。
答案 3 :(得分:1)
逐步列出卢克的想法:
(但是,你可以在决斗核心机器上做的最好的事情是将运行时间缩短一半。如果你的过程只花了4秒钟,那么可能不值得让它在2秒内运行)
使用task parallel library / Rx提供了比System.Threading.ThreadPool更友好的界面,这可能会让您的世界变得更轻松。
答案 4 :(得分:0)
你想念imho一个项目,这并不总是关于执行时间。有:
无论如何,忽略我的观点1 - 你可以在不加速的情况下进行多线程以保持你的UI响应 - 我会说你实际上要么分开工作总是那么快(所以你可以保持更多而不是一个核心繁忙)或卸载它的原因。