多线程算法优化技术

在现代计算中,多核处理器的普及使得并行计算成为了提升程序性能的重要手段。本文将探讨在多核处理器上应用线程的算法优化技术,并通过C#和C++实现的案例分析,展示如何通过减少锁操作、使用用户空间同步对象等方法来提高程序的执行效率。

问题描述

选择的问题是:对于1到1000000之间的每一个数字n,应用以下函数,直到数字变为1,同时计数应用该函数的次数。这个算法将对1到1000000之间的所有数字执行,程序将打印结果和计算结果所需的执行时间(以毫秒为单位)。测试机器的配置为:AMD Athlon 2 P340 Dual Core 2.20 GHz,4 GB RAM,Windows 7 Ultimate x64。将使用C#和C++(Visual Studio 2010)来实现这个算法。

实现

将使用一个队列来存储要处理的数字。对于每个可用的处理器核心,将创建一个工作线程。所有工作线程都操作(仅读取)这个共享队列。每个工作线程从队列中提取一个数字并计算所需的值。数字由主线程写入队列,主线程是唯一写入队列的线程。工作线程运行,直到所有数字都被处理完毕。

在C++中,将使用前一篇文章中介绍的算法。在C#中,将使用anlarke提出的算法:

for (int iCurrentCycleCount = 1; iNumberToTest != 1; ++iCurrentCycleCount) { if ((iNumberToTest & 0x1) == 0x01) { iNumberToTest += (iNumberToTest >> 1) + 1; ++iCurrentCycleCount; } else iNumberToTest >>= 1; }

优化结果

在最初的实现中,C++的执行时间非常长,这主要是由于以下两个原因:

  • 只使用了一个队列,由NumCore + 1个线程共享。
  • 执行了大量的锁定操作,以在队列中写入/读取数据。

为了解决第一个问题,将使用一个队列为每个工作线程,并将并发问题限制在主线程和每个工作线程之间。为了最小化一个线程必须等待另一个线程释放其锁的时间,将队列分成NumCore个队列。

对于第二个问题,选择不是一次写入一个数字到队列中,而是一次写入250个数字(通过测试确定的数字)。

在优化后,C++和C#的执行时间都得到了显著的改善。C++的执行时间比C#慢,因为在C++中使用互斥锁(在内核空间实现),而在C#中使用lock关键字,它使用临界区(在用户空间实现)。

  • 尽量不要在线程之间共享数据。
  • 尽量减少锁定操作的数量,因为它们是昂贵的,以块的形式处理数据,而不是一个接一个地处理。
  • 如果不需要进程间同步,请使用用户空间同步对象。
  • 如果线程遵循生产者-消费者模式,并且生产者线程必须提供给消费者线程的数据在启动消费者线程之前已知,那么可以消除锁定。
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485