【IT168 技术】未来属于多核技术时代已经得到了CPU或GPU硬件厂商的共识。因此怎样通过并行性来发挥多核的优势便提上了议程。在Visual Studio 2010中,微软引入了众多的新库和运行时,以此来简化基本代码表达并行性的过程,并且支持新工具对并行应用程序进行性能分析和调试。
从实际应用出发
并行性融入应用程序是为了利用多个内核,以前单一的顺序工作一次仅在一个内核上运行。 要使应用程序使用多个内核,需要让多项工作启用多个线程,以便对该工作进行并行处理。 这样,假如只有一项工作,那么要想通过多核执行实现并行加速,就需要将该单一工作划分为可并发运行的多个单元。
最简单的方案是静态划分: 将工作划分为固定数目、固定大小的单元。但是,这种方法仍然差强人意。 在实际环境中划分工作负荷时,很少能够保证每个单元都占用同样的处理时间,尤其在您将一些外部因素(如可能在计算机上同时运行并消耗部分计算机资源的其他工作负荷)考虑在内时。 在这种情况下,每个内核一个单元的划分最终可能会造成不均匀的工作分配: 某些线程将先于其他线程完成其单元的处理,从而造成负荷不平衡,而某些内核在其他内核完成时处于空闲状态。 为解决这一问题,您需要对工作进行深度划分,将工作负荷划分为可行的最小单元,以便计算机的所有资源都能参与工作负荷的处理,直到处理完成。
如果执行一个工作单元引起零开销,则刚刚提出的解决方法将较为理想,但很少有实际环境中的操作会引起零开销。 根据过去的经验,线程一直是用于执行这样一个工作单元的机制: 为每个工作单元创建一个线程,让其执行,然后终止该线程。 遗憾的是,线程相对来说是重型的,以这种方式使用它们所产生的开销可能会禁止我们所讲的深度划分类型。 您所需要的是一种用于执行这些已划分的单元以将开销降到最低程度的更轻型机制 — 一种可使您更放心地进行深度划分的机制。 通过这种方法,您不是为每个单元创建一个线程,而是利用一个计划程序来计划在它所管理的线程上执行的各个单元,从而在保持单元数目尽可能少的同时仍能确保实现最大吞吐量。
刚刚介绍的是一个线程池,它将线程管理成本在计划给它的所有工作项中分摊,从而将与单个工作项关联的开销降到最低。 在 Windows 中,可通过从 Kernel32.dll 导出的 QueueUserWorkItem 函数访问这种线程池。 (Windows Vista 还引入了新的线程池功能。) 在 .NET Framework 4 中,可通过 System.Threading.ThreadPool 类访问这种线程池。
调试
虽然Visual Studio 2005有一个内建的MPI程序的简单调试器,但并未提供完整的“F5”体验。在新的Visual Studio 2008 插件(同时也将集成到Visual Studio 2010中)中,您只需选择一个集群头节点以及您需要多少核,然后按F5就可以对您的MPI程序进行调试了。