关于编译器的多个同时任务的实现

时间:2012-01-09 07:48:18

标签: c++ multithreading multiprocessing compiler-construction

在努力与口译员分道扬and,并试图用c ++推进我的知识的过程中,我最近购买了“C ++ In a Nutshell:A Desktop Quick Reference(in a Nutshell(O'Reilly))”的副本“编写编译器和口译员(Wiley)”。虽然我的C ++大学课程教会了我如何对堆栈和列表进行排序,但它并没有教会我这些主题。我决定编写一个编译器,以满足我独特的习惯和编码风格。

在最近出现真正的多处理能力的情况下,值得付出的努力是什么?我完全了解大量能够提供线程和提供多处理的库。默认使用预先存在的代码并不能实现有效的学习过程,因为与个人编写的代码的旧密切联系将非常缺乏。

4 个答案:

答案 0 :(得分:1)

编译器通常被实现为管道,其中源代码在一端进行,并且多个处理步骤按顺序应用,并且对象文件在另一端出现。这种处理通常不适合多线程。

由于当今计算机的速度,编译器很少需要进行如此多的处理才能从多线程实现中受益。在一个管道中,无论如何只有一些你可以做的事情,比如并行运行每个函数的优化。

通过简单地针对多个源文件并行运行编译器,可以看到更容易的增益。这可以在编译器中没有任何多线程支持的情况下进行;只需编写一个单线程编译器(更不容易出错),让你的构建系统处理并行性。

答案 1 :(得分:1)

编写编译器很难;语言很复杂,人们想要好的代码,而且他们不想等待很长时间。根据您自己使用C ++编译器的经验,这一点应该是显而易见的。编写C ++编译器特别困难,因为语言特别复杂(新的C ++ 11标准使其变得相当复杂),人们期望C ++编译器提供非常好的代码。

所有这些复杂性以及编译器缺乏背景意味着您不太可能编写C ++编译器,更不用说并行编写器了。海湾合作委员会和CLANG社区拥有数百名人民和数十年的开发时间。为了更好地理解问题,构建玩具编译器可能是值得的。

关于编译器本身的并行性,可以采用几种方法。

第一种是使用标准库,如您所建议的那样,并尝试使用并行性来改进现有编译器。奇怪的是,鉴于GCC和CLANG是开源工具,很少有人尝试过这项任务。但是,并行设计没有并行性的程序也很困难。在哪里找到并行单元(处理单个方法?),如何插入并行性,如何确保现在改进的编译器没有同步问题(如果编译器并行处理所有方法,哪里是保证一个方法的签名实际上是准备好的,并且可用于正在编译的其他方法吗?)最后,如何确保并行工作支配额外的线程初始化/拆卸/同步开销,以便编译器在给定多个CPU时实际上更快?另外,线程库有点难以使用,并且相对容易使得对线程调用进行哑码错误编码。如果你的编译器中有很多这样的东西,你就很有可能犯这样一个愚蠢的错误。调试很难。

第二个是使用这样的库从头开始构建一个新的编译器。这需要大量工作才能使基本编译器到位,但是具有在设计期间可以考虑编译器的各个元素的优点,并且我设计的并行互锁不知道以这种方式构建的任何编译器(当然有一些像这样的研究编译器)但它的工作很多,显然比编写非并行编译器更多的工作。你仍然会遇到线程库的笨拙。

第三是找到并行编程语言,并在其中编写编译器。这样可以更容易地编写没有错误的并行代码,并且可以允许您实现线程库可能无法实现的各种并行性(例如,动态计算团队,部分命令......)。它还具有以下优点:并行语言编译器可以在代码中看到并行性,因此可以生成较低开销的线程操作。因为编译器会进行许多不同持续时间的计算,所以您不需要同步数据并行语言;你想要一个具有任务并行性的人。 我们的PARLANSE编译器是一种编程语言,旨在实现适合编译器的并行符号(例如非数字)计算。现在你需要一个并行编译器和从头开始构建新编译器的能量。

第四种方法是使用并行语言和预定义的编译器典型活动库(解析,符号表查找,流分析,代码生成)并以这种方式构建编译器。那时你不必重新发明编译器的基本功能,并且可以继续构建编译器本身。

我们的DMS Software Reengineering Toolkit就是这样一套工具和库,旨在让人们构建复杂的代码生成/转换或分析工具。 DMS有full C++11 front end可用,它使用所有DMS(并行)支持机制。

我们使用DMS来执行大规模的C ++分析和转换任务。并行性存在,并且有效;如果我们尝试,我们可以做得更多。我们还没有尝试构建一个真正的并行编译器;考虑到其他C ++编译器是免费且完善的,我们没有看到它的市场。我希望有一天会有人找到一个需要并行C ++编译器的小众场所,然后像这样的机制很可能成为一个基础;从头开始做太多的工作。

答案 2 :(得分:0)

你不太可能在真正的编码中构建对你有用的东西,特别是作为第一次学习体验 - 换句话说,价值在旅程中,而不是你在结束。这是一次学习经历。

因此,我建议您采取一些您感兴趣的事情,并惹恼您现有的语言和编译器,并尝试改进它们(或至少尝试不同的东西)。除此之外,你想要写一些尽可能简单的东西,以便你可以真正完成它。

如果你正在进行足够的多线程编程,这是你正在思考的关键部分,那么尝试编写可以进行多处理的东西可能是值得的。否则,我强烈建议您将其从第一个编译器项目中删除;它是一个复杂的大毛茸茸的巢,如果没有它,编译器是一个足够大且毛茸茸的项目。

而且,如果您认为多线程很重要,您可以随时添加它。不过,最好先拥有一些先行的东西,这样你就可以使用它来阻止你在添加更多内容时陷入困境。

哦,你绝对不想在内部制作第一个多线程编译器!从简单开始,然后在完成一次后增加复杂性,并了解所涉及的工作量。

答案 3 :(得分:0)

这取决于您希望编译的语言类型。

如果您考虑今天创建一种语言,它应该基于模块,而不是基于C ++构建的头/源方式。使用这样的语言,编译器通常被赋予单个“目标”(模块)并自动编译依赖项(其他模块),这就是Python编译器所做的。

在这种情况下,多线程会立即获得收益:您可以简单地并行化多个模块编译。这是相对容易的,只需考虑留下一个“标记”,即您正在编译给定模块,以避免并行执行多次。

进一步发展并不是立即有用的。虽然优化可能并行应用,例如,它需要注意它们应用的模型的同步。并行编译多个模块的好处是它们在编译期间大部分是独立的,只有在准备就绪时才是只读的,这可以缓解大多数同步问题。