V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
find456789
V2EX  ›  问与答

关于创建新的编程语言时,基于旧语言,如果旧语言的性能不好,是不是新语言的性能也一定不会好?

  •  
  •   find456789 · 353 天前 · 1745 次点击
    这是一个创建于 353 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我的理解是这样的:

    假如我基于 python,开发一门新语言,假设就叫 bb 语言

    首先 bb 语言的打印字符串的代码如下:

    
    打印 bb("你好")  # 这是 bb 语言的打印语句,类似 python 的 print
    
    

    由于我是基于 python 创造 bb 语言的,所以,我用 python 代码 针对 上述的 文本内容( bb 源代码),进行处理(词法分析、语法分析), 然后 python 代码里,捕捉到了 词法 打印 bb 以及 你好

    python 代码就可以知道,是要打印一段文本, 然后就调用 python 的print,并把 你好 传给print

    就这样, 完成了 基于 python 创造一门新语言 bb (目前只支持一个语法,即 打印 bb)

    我理解的其他语言,比如:
    java 基于 c ( java 的printf本质是调用 c 的printf),
    cpython 基于 c ( cpython 的print本质是调用 c 的printf) ,

    所以,如果我基于 python 创造了 bb 语言,那么 bb 语言的 打印 bb 本质就是调用 python 的print

    不知道我的理解对不对


    如果 我的以上理解是正确的, 那么,假如 python 的print性能很差,那么是否 bb 语言的 打印 bb 也一定会很差?

    如果以上假设成立,那么 假如 在我的 bb 语言里,我给打印 bb这个方法加了更多额外处理流程,比如,在执行 打印 bb的时候,还检测了网络,还读取了 xx 信息,总之 要 10 秒才能打印出内容

    那么,某一天,有人基于 bb 语言,创造了 cc 语言,cc 语言的 打印 cc 基于 bb 语言的 打印 bb,那么,cc 语言的 打印 cc被调用后,也会有 10 秒多的延迟吧? 也会检测网络,读取 xx 信息 对吧?

    那么,那些基于 c 的语言,如 java 、cpython,是怎么确保 基于 c 语言开发时,不会被 c 语言自身的私货(即 bb 语言里的 检测网络,读取 xx 信息 ) 影响了性能呢?

    那么在这种情况下, 自举 还能提高性能吗? 不就变成了 套娃了吗? 最开始的娃很卡(如 bb 语言的打印 bb), 以后套上的娃 性能肯定不会超过最初的娃吧

    有人基于 bb 语言,创造了 cc 语言,并且在 打印 cc 还加了自己的处理流程, 打印 cc 的延迟成功的增长到了 20 秒, 后来 又有人 基于 cc 语言创造了 dd 语言, ..... ... 直到 zz 语言,这时候 打印 zz 的 延迟很高很高了吧?

    套娃,越来越卡,各种历史包袱, 导致更卡了

    我的理解对吗

    跪求各位前辈指点

    谢谢

    24 条回复    2020-12-09 22:28:47 +08:00
    ysc3839
        1
    ysc3839   353 天前 via Android   ❤️ 1
    > 那么 bb 语言的 打印 bb 本质就是调用 python 的 print
    这句话作为前提的情况下,bb 语言性能是会更差的。

    但是这句话不能作为结论,bb 语言完全可以不用 Python 的 print 。

    比如 Python 允许你直接调用系统 API,那你完全可以直接用最底层的 API,不用 Python 的 print 。
    BoarBoar
        2
    BoarBoar   353 天前   ❤️ 2
    什么叫基于 xx 语言创建一门语言啊。。
    java 和 python 也不是基于 C 创建的,只不过是用 C 写的编译器
    不管啥语言都会被编译器翻译成二进制机器语言,计算机也只认识机器语言
    你理解的那种 cc 先翻译成 bb 再翻译成 aa 的,只有中文编程的骄傲易语言
    cmostuor
        3
    cmostuor   353 天前
    @BoarBoar 这还真是 早期版本的易语言是会把中文写的代码翻译成英文然后编译
    ysc3839
        4
    ysc3839   353 天前 via Android
    @BoarBoar
    > 不管啥语言都会被编译器翻译成二进制机器语言
    不一定的,比如 Python 就是解释执行的,不会生成机器代码。

    @cmostuor 没记错的话易语言一开始就是自己实现的编译器,不依赖其他语言的编译器。
    msg7086
        5
    msg7086   353 天前   ❤️ 2
    @BoarBoar @cmostuor @ysc3839
    易语言我记得一开始是解释执行,后来 3.0 的时候全部本地编译了,只依赖运行时,不需要解释器。
    二十年前的事情了,如果有记错的话请纠正。

    @find456789
    新语言不需要基于某种语言。
    Java 的 printf 并不一定要调用 C 的 printf,你也可以用 Java 自己实现。
    C 的 printf 也不一定要是 C 写的,你完全可以汇编,或者别的语言来写(比如 Rust 或者 Go )。

    归根结底,CPU 执行的是机器码,你运行的程序最终都是机器码。
    只要一段机器码能实现相关的功能,用任何语言去写都是一样的。
    语言只是书写工具,是让你方便地写出最终能编译成机器码的东西。
    比如说计算两个整数的和,最终都是回到 ADD 指令,那么「 1 加 2 」完全可以直接编译成 MOV ax, 1; ADD ax, 2 而不是去调用 Python 的加法函数。
    beidounanxizi
        6
    beidounanxizi   353 天前   ❤️ 2
    你的理解真的很民科啊 语言又不是左右性能的因素 🐶
    Kininaru
        7
    Kininaru   353 天前 via Android
    你知不知道有的 C 编译器里面有 Python 组件。。。如果你高兴的话,也可以用 Java 写一个 C 编译器,只要算法相同,编译出来的东西是完全一样的,执行速度也一样,唯一不同的就是编译耗时
    namaketa
        8
    namaketa   353 天前   ❤️ 2
    新语言( x )
    DSL (√)
    你想的很对,所以一般高级语言不会用另一个高级语言做中间码,而是到更加低级的 C 或者机器码。
    编译器套编译器,虚拟机套虚拟机这种事还是比较蠢的。
    效率还不是主要问题...而是 debug 可能会让你崩溃。
    si
        9
    si   353 天前   ❤️ 1
    @msg7086 确实是,易语言刚开始是解释执行的,后面的版本才编译成机器码的。不过生成的机器码质量比较差,基本没有优化,而且数值运算都是基于浮点数的。
    msg7086 已经说得很清楚了,用什么语言实现并不影响目标语言的程序性能。关键看你的语言的编译器生成的是什么。
    python 可以读写二进制文件,即使你用 python 写编译器,这个编译器也可以直接生成机器码。
    python 的性能只影响编译器的性能,可能编译时间会比较久一点。编译出来的目标程序性能怎么样要看你写的编译器生成的程序质量怎么样。
    如果你的编译器是生成 python 代码,目标程序要在 python 上执行,就会受到 python 的影响。
    如果你的编译器直接生成 c 代码,那就要在调用 c 编译器编译成可执行文件,就会受到 c 编译器的影响。
    如果你的编译器直接生成机器代码,输出可执行文件,那就看你的编译器生成的结果怎么样,其他语言不会影响程序性能。
    misaka19000
        10
    misaka19000   353 天前
    太民科了。。。

    语言分为 runtime 和编译器,你所理解的应该是 runtime
    shroxd
        11
    shroxd   353 天前 via iPhone
    @BoarBoar 老哥你忘了 TypeScript
    muzuiget
        12
    muzuiget   353 天前   ❤️ 1
    确实民科了,根本就没有关系。JS 都有 N 个语言实现,所谓解释执行并不是真的一行一行边读边解析,而是先解析生成字节码,然后再对字节码运行。
    find456789
        13
    find456789   353 天前
    @ysc3839
    @BoarBoar
    @cmostuor
    @ysc3839
    @msg7086
    @beidounanxizi
    @Kininaru
    @namaketa
    @si
    @misaka19000
    @shroxd

    谢谢大家, 我刚才看了很多资料, 我感觉我上面的描述,应该是指解释器, 我现在利用 antlr 实现了一个 bb 语言的雏形, 可以通过 在 shell 执行 ./bb_lang a.bb 来执行 a.bb 里的代码

    bb_lang 的代码如下:
    ![image.png]( https://i.loli.net/2020/12/09/T2cMLUBWvNJtoRX.png)


    a.bb 的代码:
    ![image.png]( https://i.loli.net/2020/12/09/gIcQY8lnGTUh5WE.png)

    visitror.py 核心代码:

    ![image.png]( https://i.loli.net/2020/12/09/bil9vtOsqU71Jrw.png)

    在这里面,我的 方法 `打印` 就是直接调用 python 的 print

    加, 就是直接调用 python 的 加法运算符
    减 也类似

    所以在发帖的时候,我才会觉得,基于另外一个语言来开发新语言,就类似套娃




    所以我现在还是有些糊涂,我可能需要再看一些书
    msg7086
        14
    msg7086   353 天前   ❤️ 1
    @find456789 DSL 或者解释运行的代码,的确如你所说,是会变慢的。
    慢是慢在解释运行,而不是语言。

    语言甚至都没有速度,因为语言只是一些语法文法规则而已。
    怎么把这些语法文法跑起来,不同的跑法速度是不同的。
    sagaxu
        15
    sagaxu   353 天前 via Android
    pypy 了解一下?
    ipwx
        16
    ipwx   353 天前   ❤️ 1
    解释型语言也不一定比 native code 慢,因为有 JIT 。

    用 Python 写的解释性语言 interpreter 也不一定比 Python 慢,因为有 JIT 。参考 PyPy 。
    Cbdy
        17
    Cbdy   353 天前 via Android
    答案是不一定
    12tall
        18
    12tall   353 天前
    如果你能将 bb 翻译为机器码,可能比 python 还要快哦
    cmostuor
        19
    cmostuor   352 天前
    @msg7086 没错 3.0 之前的那会我下载来分析过 分析完了还在社交网络发吐槽 没记错的话
    BoarBoar
        20
    BoarBoar   352 天前
    @ysc3839 我没表达严谨,没说解释型语言的情况。
    但是动态语言也一样是由解释器或者 runtime(例如 jvm)动态编译成机器码动态执行,cpu 除了 0101 根本不认识其他东西。
    secondwtq
        21
    secondwtq   352 天前   ❤️ 1
    不一定。“基于旧语言创建新的语言”的方法,比茴的写法都要多很多。
    我猜测楼主这种想法可能是受了某些人“所有语言都差不多”,“学语言就是学库”之类言论的影响。

    首先要明确,编程语言存在的意义是充当人与机器沟通过程中的编码形式,程序员输入的表面上是代码,实际的东西是隐藏在代码中的 “计算”。
    一个循环在不同的语言中有不同的写法,就好象乳法有不同的乳法,但是最后都是循环,都是乳法,这一“本质”不因具体的实现方法而不同。

    然后要区分语言和语言实现,语言定义了计算的编码形式,而语言实现将该语言所编码的计算在特定的平台上执行。同一个语言可以有多种实现,可以“基于”不同的语言,从这一点上来说,标题所提出的问题的答案就是否定的。

    再然后是编程语言的性能,语言的性能应该定义为“不同编程语言进行同样计算时的性能”,但是需要注意的这里的“计算”是使用编程语言编码的,编程语言本身定义了计算的抽象模型,也就是说基本上在进行任何有意义的比较时,比较的都不是完全一致的计算。而从实际意义来讲,“计算”本身是解决问题的工具,所以一般在讨论“编程语言的性能”时,讨论的是使用不同编程语言解决同样问题的性能差异。但是人们使用编程语言解决问题时使用的并不是这个编程语言的定义本身,而是编程语言(即计算模型)的特定具体实现,因此其实是“使用特定的编程语言实现解决特定问题时的性能”。

    但是就算同样是“使用特定的编程语言实现解决特定问题”,也有不同的方法。比如同样是大数组的排序,C 用插入排序,Python 用快排,就不太合适。这个具体的方法可以被叫做“算法”,但是由于上面提到的不同语言之间计算模型的差异,“算法”也不具备直接的可移植性。在一个语言实现中高效的算法,在另一个语言实现中不一定高效。所以其实就算是同一个语言的不同实现,也没有什么太大的可比性。另一个讨论“性能”时经常被过度简化的是“问题”,这一点其实在讨论硬件时尤其明显,吃瓜群众往往希望能获得一个简单的答案“硬件 A 比硬件 B 的性能高百分之几”,但是性能问题本来就不是这么简单的,在解决某一个问题上的优化,对于另一个问题来讲可能就是劣化。而这种心理正好被 marketing 利用,因为这样他们可以 cherry pick 并着重宣传好的方面,引导大众不去关注不那么好的方面。

    再说说硬件,目前的计算机硬件不理解问题,更无法直接帮你解决问题。其厂商定义了自己的计算模型,硬件本身则提供这一模型的具体实现,这是一切软件工作的基础。原则上硬件是编程语言实现的一部分,但是在实际应用中的关系要更加微妙。特别是在研究性能问题时,具体讨论的对象往往取决于实际情况。比如一般会要求硬件条件是一样的,同时硬件需要操作系统、驱动程序等环境支持,这些应该也保持一致。考虑到现实中绝大多数编程语言实现者一般只有选择硬件和操作系统而没有影响它们的能力,绝大多数情况下也是将这些都排除在“编程语言实现”范围之外的。但是在比较 Kotlin 和 Scala 的性能时,JVM 也应该保持一致。就连比较两个 C 实现的性能,也需要考虑内存分配器的影响。“保持一致”并不能完全解决问题,整个编程语言实现中,不同的模块和不同的配置方式可能会体现出不同的性能特点。

    所以这是楼主所提出的“编程语言”和“性能”,以及把这两个词放在一块时,背后的水有多深,简单来说就是基本没法谈,楼主的问题也就没什么意义。

    (哦对我还没说“性能”的度量有多个维度,包括但不限于延迟、吞吐量、功耗、存储占用等)

    那一般人们说的编程语言的“性能”指的是什么呢,其实只要把上面几个比较 tricky 的部分都加上“约定俗成的”就可以了:
    * 比如,第一个问题是语言实现的问题,“约定俗成的语言实现”指的一般就是一个编程语言的 de facto standard 实现,或者主流实现。
    * 之后是硬件及软件环境问题,这个一般把两个语言实现纵向来看,能保持一致的都要保持一致,但也不仅仅是“保持一致”那么简单。在这里有可比性的前提是:在同样的硬件+操作系统组合下,存在语言的主流实现,并且该组合是该主流实现的主要目标之一。
    * 然后是“算法”问题,对于某个特定的问题,“约定俗成的”一般采用一个使用该语言的平均水平的程序员解决这一问题时会采用的“算法”。
    * 最后是具体解决什么“问题”的问题,这个就多了,比较“约定俗成的”有光线追踪、计算 pi 、mandelbrot 、矩阵乘、正则匹配、数独、词典计数、Web 服务器等。如果一个编程语言实现相对于另外一个,在大多数“问题”上表现都没有优势,并且有相当一部分“问题”有明显差距的话,那么就说这个实现的性能(或者说“平均性能”)不如另外一个。

    可见其中可以做手脚的部分非常多。

    上面已经说了,现实中绝大多数编程语言实现者没有影响硬件和操作系统的能力,因此编程语言实现一般会选择将其源编程语言所定义的模型,映射到另一个模型。这就是说“用另一个模型实现某个模型”。其性能主要取决于两个因素,一是所映射到的目标计算模型的性能上限(当然计算模型本身是没有性能 /性能上限的,所以这里指的是具体实现的性能上限),二是实现本身做这个映射的效果。

    这里有个“性能上限”,这是我自己 coin 出来的词。指的是一个程序员,熟练掌握接化发,能够在特定的语言框架内,写出这个语言解决某个问题性能最高的程序。这个“性能最高的程序”所达到的性能,称为“性能上限”,这个程序员则称为一个“Surprisingly Smart Programmer”。当然这个性能依然是需要在特定的实现上。这里主要是解除了“约定俗成”中“平均水平程序员”的限制。
    之所以提出“性能上限”和“Surprisingly Smart Programmer”这两个概念,是为了引申出“Surprisingly Smart Compiler”,或者“Surprisingly Smart Programming Language Implementation”这个概念,本来程序员需要使用其他计算模型来表达算法,但是编程语言实现允许程序员使用新的计算模型,如果编程语言实现可以做到“Surprisingly Smart”的话,那么就不需要“Surprisingly Smart Programmer”了。编程语言实现就可以发挥出目标计算模型的所有性能潜力。
    (这俩词依旧是我 coin 出来的,为的是和已有的“Sufficiently Smart Compiler”这一概念保持一定的联系同时又有一定的区别,按照 C2 上的定义,“Sufficiently Smart Compiler” 只要“as fast as C”就可以了,“Surprisingly”更强调“上限”,你懂么,就是传统功夫四两拨千斤的本事)

    再来说第二个因素,现实中不存在“Surprisingly Smart Programmer”,更不存在“Surprisingly Smart Compiler”。现实情况是——不同编程语言实现的智商(也就是上面所说的“实现本身做这个映射的效果”)各不相同,有些很低,有些还凑合,有些高一点。但是最高也高不过某个上限,这个上限目前大概在“Sufficiently Smart”这一级别,做到这一级别的都很少。这两个概念的意义在于思考实验,假设编程语言实现 C 基于目标实现 T 实现了一个新的计算模型:
    * C 的“性能上限”不会高于 T 的“性能上限”。
    * 如果 C 是一个“Surprisingly Smart Compiler”,那么 C 的“平均性能”也可以达到 T 的“性能上限”。
    * 但是尚不存在“Surprisingly Smart Compiler”,C 最多只能做到“Sufficiently Smart”,也就是说两者的“平均性能”和“性能上限”都差不多。
    * 如果 C 连“Sufficiently Smart”都做不到(很有可能),那么 C 可能连“性能上限”都比 T 差一截。这时就连“Surprisingly Smart Programmer”都不能使 C 的性能超越 T 。
    * 但是 All is not lost. 无论 C 做成什么样,在特定情况下的性能是有可能超过 T 的平均性能的。
    * 在“Surprisingly Smart Compiler”不存在的情况下,一般 C 和 T 所实现的计算模型差别越小,控制 C 和 T 的“平均性能”和“性能上限”的差距对 C 的实现智商要求越低。

    目前主流编程语言中,平均性能和性能上限最高的均为 C/C++,C/C++ 的主流实现将 C/C++ 代码映射为目标硬件的汇编,并且会进行大量的优化变换,更别说这些主流实现还提供大量的非标准扩展,比如内联汇编在 UNIX 平台上基本是事实标准。也就是说在 C/C++ 的主流实现中,目标计算模型实现基本上是最高性能的,其实现本身又基本是最高效的,C/C++ 所定义的计算模型和其目标的差别也不大(尤其是考虑到非标准扩展)。
    理论上其他编程语言实现可以在性能方面超越这些 C/C++ 的主流实现,但是目前 C/C++ 是三方面全面优势,其他编程语言得一个个推翻这三座大山,短时间内希望不大。还是要以和为贵,点到为止。

    比如楼主给自己的 E 语言(大 E 了没有闪,说明很快啊)做了一个实现,映射为 Python 语言。按照刚才那一套民科理论,该 E 语言实现的性能就取决于实现本身的质量,和目标 Python 语言实现的性能。而要提高该实现的性能,也可以应用刚才的理论,比如改变目标实现,使用比 Python 主流实现 CPython “性能更好”的 Python 实现,并把基于这个实现做出来的 E 语言实现钦定为 E 语言的“主流实现”,这样按照刚才的定义就比 Python 性能更好了。或者提高 E 语言实现自身的质量,比如想办法检测代码中可以并行的计算,使用多进程或 GPU 来实现这些计算——大多数人写 Python 不会常用到这些东西的,依然可以在刚才的定义上完成对 Python 性能的超越。
    secondwtq
        22
    secondwtq   352 天前   ❤️ 1
    哦对,还有,编程语言实现“将一种计算模型映射到另一种计算模型”,这个也算是一个“问题”,无论其源和目标是什么,这个“问题”都可以由多种计算模型,多种算法来解决。
    因此把 E 语言映射到 Python 的工作,可以使用 Python 完成,也可以使用其他编程语言完成。Python 可以把 E 语言映射到 Python,也可以把 E 语言映射到 JVM 。这一过程一般就是纯粹的“计算”,甚至可以不需要 FFI 。

    GitHub 上的很多编译器项目都是直接拉下来就能构建,额外的依赖很少。
    然后我现在硬盘里有个尚未构建成功的 Chromium ...
    find456789
        23
    find456789   352 天前
    @secondwtq 谢谢
    lithbitren
        24
    lithbitren   352 天前
    最多只能算替换关键字或关键字映射,连语法解析规则都没变,更别说解释器和编译器的实现了。。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2045 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 01:47 · PVG 09:47 · LAX 17:47 · JFK 20:47
    ♥ Do have faith in what you're doing.