Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
方程分析器效率 我在一个本地C++方程分析器中沉没了大约一个月的时间。除了速度慢(比硬编码方程式慢30-100倍)外,它还能工作。我可以做些什么来加快速度_C++_Performance_Parsing_Equation - Fatal编程技术网

方程分析器效率 我在一个本地C++方程分析器中沉没了大约一个月的时间。除了速度慢(比硬编码方程式慢30-100倍)外,它还能工作。我可以做些什么来加快速度

方程分析器效率 我在一个本地C++方程分析器中沉没了大约一个月的时间。除了速度慢(比硬编码方程式慢30-100倍)外,它还能工作。我可以做些什么来加快速度,c++,performance,parsing,equation,C++,Performance,Parsing,Equation,我阅读了所有关于高效代码的资料。概括地说: 解析器将字符串表达式转换为“操作”对象列表 操作对象有两个函数指针:“getSource”和“evaluate” 为了计算一个等式,我所做的就是在操作列表上创建一个for循环,依次调用每个函数 当计算一个等式时,没有遇到一个if/开关-所有条件都是由解析器在最初分配函数指针时处理的 我尝试内联函数指针指向的所有函数-没有改进 从函数指针切换到函子会有帮助吗 删除函数指针框架,而是创建一整套派生的“操作”类,每个类都有自己的虚拟“getSource

我阅读了所有关于高效代码的资料。概括地说:

  • 解析器将字符串表达式转换为“操作”对象列表
  • 操作对象有两个函数指针:“getSource”和“evaluate”
  • 为了计算一个等式,我所做的就是在操作列表上创建一个for循环,依次调用每个函数
当计算一个等式时,没有遇到一个if/开关-所有条件都是由解析器在最初分配函数指针时处理的

  • 我尝试内联函数指针指向的所有函数-没有改进
  • 从函数指针切换到函子会有帮助吗
  • 删除函数指针框架,而是创建一整套派生的“操作”类,每个类都有自己的虚拟“getSource”和“evaluate”函数,怎么样?(但这不只是将函数指针移动到vtable中吗?)

我有很多代码。不确定提取/发布什么。询问它的某些方面,您将收到。

在您的帖子中,您没有提到您已经分析了代码。如果我处在你的位置,这是我要做的第一件事。它会让您很好地了解时间花在哪里,以及优化工作的重点。

第一件事是:分析实际出了什么问题。瓶颈是解析还是评估?valgrind提供了一些可以帮助您的工具


如果是在解析中,boost::spirit可能会帮助您。如果在计算中,请记住虚拟函数的计算速度可能非常慢。我对递归boost::variant有很好的体验

您知道,构建表达式递归下降解析器非常简单,表达式的LL(1)语法只是几个规则。然后解析就变成了一个线性事件,其他一切都可以在表达式树上工作(而解析基本上是);您将从较低的节点收集数据,并将其传递给较高的节点进行聚合


这将完全避免使用函数/类指针来确定运行时的调用路径,而不是依赖已证明的递归性(或者,如果愿意,您可以构建一个迭代LL解析器)。

很难从您的描述中分辨出慢度是否包括解析,或者只是解释时间

如果将解析器编写为递归下降(LL1),那么它应该是I/O绑定的。换句话说,解析器读取字符和构建解析树所需的时间应该比将文件读入缓冲区所需的时间少得多

解释是另一回事。 解释代码和编译代码之间的速度差通常慢10-100倍,除非基本操作本身很长。 也就是说,您仍然可以对其进行优化

您可以分析,但在这种简单的情况下,您也可以在调试器中,在单个指令级别单步执行程序。 这样一来,你就“站在电脑的立场上”了,很明显还有什么可以改进的

无论何时我在做您正在做的事情,即向用户提供一种语言,但我希望该语言能够快速执行,我所做的是: 我将源语言翻译成我有编译器的语言,然后动态编译成.dll(或.exe)并运行它。
它非常快,我不需要编写解释器,也不需要担心它有多快。

看起来您使用的是一个非常复杂的数据结构(据我所知,是一个带有指针的语法树等)。因此,遍历指针解引用不是非常有效的内存方式(大量随机访问),可能会显著降低速度。正如Mike Dunlavey所建议的,您可以在运行时使用另一种语言或通过嵌入编译器(如LLVM)编译整个表达式。据我所知,Microsoft.Net为反射.Emit和Linq.Expression树提供了此功能(动态编译)。

这是我建议暂时不要分析的少数几次。我的直接猜测是,您使用的基本结构才是问题的真正根源。在您合理地确定基本结构是合理的之前,对代码进行分析很少有什么价值,主要是找到基本结构的哪些部分可以改进。当你真正需要做的是扔掉大部分你拥有的东西,然后重新开始的时候,它就没有那么有用了

我建议将输入转换为RPN。要执行此操作,唯一需要的数据结构是堆栈。基本上,当你得到一个操作数时,你把它推到堆栈上。当您遇到运算符时,它会对堆栈顶部的项进行操作。对格式良好的表达式求值后,堆栈上应该只有一项,即表达式的值


只有像@Mike Dunlavey建议的那样,生成源代码并通过一个“真正的”编译器运行,才能获得比这更好的性能。然而,这是一个相当“沉重”的解决方案。如果你真的需要最大的速度,这显然是最好的解决方案——但是如果你只是想改进你现在正在做的事情,转换成RPN并进行解释,这通常会为少量代码提供相当不错的速度改进。

据我所知,内联只是对编译器的提示,而不是命令。可能尝试使用优化(
-O3
或其他方法)进行编译。事实上,您不能通过指针动态地内联调用的函数,因为编译器不知道您实际调用的函数(如果有的话)。也许您应该考虑在运行时输出字节码。在Windows上,可以指定