【问题标题】:The state of programming and compiling for multicore systems多核系统的编程和编译状态
【发布时间】:2011-04-08 12:39:32
【问题描述】:

我正在研究多核处理器;具体来说,我正在研究为多核处理器编写代码以及为多核处理器编译代码。

我很好奇该领域目前会阻止广泛采用编程技术和实践以充分利用多核架构的力量的主要问题。

我知道以下努力(其中一些似乎与多核架构没有直接关系,但似乎与并行编程模型、多线程和并发性有更多关系):

  • Erlang(我知道 Erlang 包含促进并发性的结构,但我不确定它究竟是如何用于多核架构的)
  • OpenMP(似乎主要与多处理和利用集群的力量有关)
  • Unified Parallel C
  • Cilk
  • Intel Threading Blocks(这似乎与多核系统直接相关;因为它来自英特尔,所以很有意义。除了定义某些编程结构外,它似乎还具有告诉编译器优化多核架构代码的功能)李>

总的来说,根据我对多线程编程的一点经验,我知道考虑到并发和并行性的编程绝对是一个困难的概念。我也知道多线程编程多核编程是两个不同的东西。在多线程编程中,您要确保 CPU 不会保持空闲(在单 CPU 系统上。正如 James 指出的那样,操作系统可以调度不同的线程在不同的内核上运行——但我更感兴趣的是描述来自语言本身,或通过编译器)。据我所知,您无法真正进行并行操作。在多核系统中,您应该能够执行真正的并行操作。

所以在我看来,目前多核编程面临的问题是:

  • 多核编程是一个困难的概念,需要高超的技能
  • 当今的编程语言中没有原生结构可以为多核环境的编程提供良好的抽象
  • 除了 Intel 的 TBB 库之外,我还没有发现其他编程语言在利用多核架构的强大功能进行编译(例如,我不知道 Java 或 C# 编译器是否优化了多核系统的字节码或即使 JIT 编译器这样做)

我很想知道可能存在哪些其他问题,以及是否有任何解决方案可以解决这些问题。链接到研究论文(和那种性质的东西)会很有帮助。谢谢!

编辑

如果我必须将我的问题浓缩为一句话,那就是:当今多核编程面临哪些问题,该领域正在进行哪些研究来解决这些问题?

更新

在我看来,多核需要关注三个层面:

  1. 语言级别:抽象并行化和并发性并使程序员能够轻松表达相同内容的构造/概念/框架
  2. 编译器级别:如果编译器知道它正在编译的架构,它可以优化该架构的编译代码。
  3. 操作系统级别:操作系统优化运行的进程,并可能调度不同的线程/进程在不同的内核上运行。

我在 ACM 和 IEEE 上进行了搜索,并找到了一些论文。他们中的大多数人都在谈论并发思考是多么困难,以及当前的语言如何没有适当的方式来表达并发性。有些人甚至声称我们当前的并发模型(线程)不是处理并发的好方法(即使在多核上)。我有兴趣听听其他意见。

【问题讨论】:

  • 您能解释一下并行编程模型和多线程的设计与多核编程有何不同吗?
  • 如果您的语言支持多核并且您的操作系统支持良好,它可以确保线程在不同的内核或处理器上,因此您的多线程应用可以并发运行。
  • 您可能想阅读stackoverflow.com/questions/181284/… 并更好地理解该主题。
  • @James 我认为并行编程和多核编程比多线程和多核编程有更多的共同点。我应该在我的问题中提到我在谈论单 CPU 系统上的多线程。我可以看到操作系统如何安排不同的线程在不同的内核上运行,但我更感兴趣的是使用语言/编译器本身来描述并行性。
  • @Vivin,至少从开发的角度来看,并行/多线程/多核编程之间确实没有区别。 Intel Threading Blocks 和 OpenMP 等库只是通过隐藏细节使并行化更容易的抽象。多核编程本质上与多处理器编程相同(但魔鬼在细节中)。您只需拥有 1 个以上的物理 CPU 即可在其上执行线程。此外,您有时会发现单处理器和多处理器机器之间的行为不同。

标签: multicore


【解决方案1】:

我很好奇该领域目前会阻止广泛采用编程技术和实践以充分利用多核架构的力量的主要问题。

惯性。 (顺便说一句:这几乎是对所有“阻碍广泛采用的因素”问题的答案,无论是并行编程模型、垃圾收集模型、类型安全模型还是节能汽车。)

自 1960 年代以来,我们就知道线程+锁模型从根本上被打破了。到 1980 年左右,我们有十几个更好的模型。然而,当今使用的绝大多数语言(包括 1980 年后从零开始新创建的语言)仅提供线程+锁。

【讨论】:

  • 谢谢!有哪些更好的模型?我假设您在谈论演员模型和“承诺和未来”?我发现这在并发/协调语言中很常见。
  • @Vivin Paliath:join-calculus,π-calculus,actor模型,CSP,一般的消息传递,数据流,嵌套数据并行,软件事务内存,一般的事务,代理,...有很多很多,我们真的还没有发现哪些有效。我们只知道线程+锁。只要我们还没有弄清楚,我就喜欢 Clojure 模型:与其选择一个并发模型,不如提供一个健全的 update 模型并构建许多不同的并发模型(我相信 Clojure 中有 6 个1.2 现在)最重要的是。
【解决方案2】:

多核编程的主要问题与编写任何其他并发应用程序相同,但是在计算机中有多个 CPU 之前并不常见,现在很难找到任何只有一个内核的现代计算机,所以,要利用多核、多 cpu 架构存在新的挑战。

但是,这个问题是一个老问题,每当计算机体系结构超越编译器时,后备解决方案似乎就是回到函数式编程,因为如果严格遵循该编程范式,可以制作非常可并行化的程序,就像你不知道的那样'例如,没有任何全局可变变量。

但是,并非所有问题都可以使用 FP 轻松解决,因此目标是如何轻松让其他编程范式在多核上易于使用。

首先,许多程序员都避免编写好的多线程应用程序,因此没有做好充分准备的开发人员数量,因为他们学习的习惯会使他们的编码更难编写。

但是,与 cpu 的大多数更改一样,您可以查看如何更改编译器,为此您可以查看 Scala、Haskell、Erlang 和 F#。

对于库,您可以查看 MS 的并行框架扩展,作为一种更容易进行并发编程的方法。

它正在工作,但我最近在 IEEE Spectrum 或 IEEE Computer 发表了关于多核编程问题的文章,因此请查看 IEEE 和 ACM 关于这些问题的文章,以获得更多关于正在研究的内容的想法.

我认为最大的障碍是很难让程序员改变他们的语言,因为 FP 与 OOP 非常不同。

除了开发能够以这种方式正常工作的语言之外,还有一个研究领域是如何处理访问内存的多个线程,但是,与该领域的许多方面一样,Haskell 似乎处于测试想法的最前沿,所以你可以看看 Haskell 是怎么回事。

最终会有新的语言出现,而且可能我们有 DSL 来帮助对开发人员进行更多抽象,但如何对程序员进行这方面的教育将是一个挑战。

更新:

您可能会发现第 24 章并发和多核编程感兴趣,http://book.realworldhaskell.org/read/concurrent-and-multicore-programming.html

【讨论】:

  • 非常感谢——我现在正在查看 ACM 和 IEEE 文章。另外,感谢您提供指向 haskell 书的链接。
  • 接受这个。希望我也能接受 Jörg 的回答!两者都是很好且内容丰富的答案。
【解决方案3】:

其中一个答案提到了 .NET Framework 的并行扩展,因为您提到了 C#,所以我肯定会对此进行调查。微软在那里做了一些有趣的事情,尽管我不得不认为他们的许多努力似乎更适合 C# 中的语言增强,而不是用于并发编程的单独和独特的库。但我认为他们的努力值得称赞和尊重,因为我们早早来到了这里。 (免责声明:大约 3 年前,我曾经是 Visual Studio 的营销总监)

英特尔线程构建模块也很有趣(英特尔最近发布了一个新版本,我很高兴下周前往英特尔开发者论坛了解如何正确使用它的更多信息)。

最后,我在西雅图的一家软件质量初创公司 Corensic 工作。我们有一个名为 Jinx 的工具,旨在检测代码中的并发错误。 30 天试用版适用于 Windows 和 Linux,因此您可能想查看一下。 (www.corensic.com)

简而言之,Jinx 是一个非常薄的虚拟机管理程序,当它被激活时,它会滑入处理器和操作系统之间。 Jinx 然后智能地获取执行切片并运行各种线程时序的模拟以查找错误。当我们发现会导致错误发生的特定线程计时,我们会在您的机器上使该计时“成为现实”(例如,如果您使用的是 Visual Studio,调试器将在该点停止)。然后,我们指出代码中导致错误的区域。 Jinx 没有误报。当它检测到一个错误时,它肯定是一个错误。

Jinx 可以在 Linux 和 Windows 上运行,并且可以在本机代码和托管代码中使用。它与语言和应用程序平台无关,可以与您现有的所有工具一起使用。

如果您检查了它,请向我们发送反馈,说明哪些有效,哪些无效。我们一直在一些大型开源项目上运行 Jinx,并且已经看到 Jinx 发现错误的速度比简单的压力测试代码快 50-100 倍。

【讨论】:

    【解决方案4】:

    任何旨在有效利用多个处理器/内核的高性能应用程序(用 C 或 C++ 编写)的瓶颈是内存系统(缓存和 RAM)。单个内核通常会通过其读取和写入使内存系统饱和,因此很容易理解为什么添加额外的内核和线程会导致应用程序运行速度变慢。如果一行人一次只能通过一个门,那么增加额外的队列不仅会堵塞门,还会降低任何人通过门的效率。

    任何多核应用程序的关键是优化和节省内存访问。这意味着将数据和代码结构化为尽可能多地在它们自己的缓存中工作,这样它们就不会通过访问公共缓存 (L3) 或 RAM 来干扰其他内核。有时,核心需要在那里冒险,但诀窍是尽可能减少这些情况。特别是,数据需要围绕缓存行及其大小(目前为 64 字节)进行结构化和调整,代码需要紧凑,不能到处调用和跳转,这也会破坏管道。

    我的经验是,有效的解决方案对于相关应用程序来说是独一无二的。通用指南(上图)是构建代码的基础,但分析结论导致的调整变化对于那些自己没有参与优化工作的人来说并不明显。

    【讨论】:

      【解决方案5】:

      查找 fork/join 框架和工作窃取运行时。相同或至少相关的方法的两个名称,即递归地将大型任务细分为轻量级单元,以便利用所有可用的并行性,而无需事先知道有多少并行性。这个想法是它应该在单处理器上以串行速度运行,但在多核上获得线性加速。

      如果你没看错的话,有点像缓存遗忘算法的水平模拟。

      但我想说多核编程面临的主要问题是绝大多数计算仍然顽固地串行。只是没有办法在这些计算中抛出多个核心并让它们坚持下去。

      【讨论】:

        猜你喜欢
        • 2010-12-30
        • 1970-01-01
        • 2016-11-19
        • 1970-01-01
        • 2011-12-10
        • 2021-04-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多