提到编程语言,大多数的文章内容都这样的:Java 已死?Ruby 的“消亡史”;编程语言排行榜:Go 最流行,Rust 最有前途;Go 语言已经全面碾压 Python…
相信很多读者都已经阅读疲劳了,所以我们这次另辟蹊径,从更有趣的视角来看编程语言,分别是编程语言的启动时间和关键字,帮助开发者更深刻和全面的认识编程语言。
谁的启动时间最少?Go 语言的启动时间是 C 语言的 300 多倍
为什么我们要观察不同编程语言的启动时间呢?因为编程语言的启动时间对于短时间运行的程序非常重要,这些程序由用户交互调用,或者由其他程序(多次)调用。
版本控制系统 Git 是用 C 编写的,调用的命令(如 Git status 和 Git log)执行速度很快。版本控制系统 Bazaar 和 Mercurial 是用 Python 编写的,它们的执行时间比 Git 长得多,并且这种速度的快慢是可被程序员感知到的,导致这种速度差异的主要原因就是 Python 启动时间占据了执行时间的大部分。
为了验证每种编程语言的启动时间各是多少,GitHub 上的一位开发者 bdrung 专门设置了一个小小的项目,项目由许多不同语言的 hello world 程序和一个简单的 Makefile 组成,Makefile 编译程序并运行基准测试,每个程序通过一行代码(使用一个很小的 run.c 程序来最小化调用的开销)运行 1000 次:
time -f “%e” taskset -c 0 ./run 1000 $program
在运行基准测试之前,安装相关的编译器,如果是在 Debian / Ubuntu 上,可以运行 make install 以安装编译器,然后通过调用 make 启动基准。
测试结果如下:
| Language | version | Intel Core i5 2400S | Raspberry Pi 3 | 
|---|
| Pascal (fpc) | 3.0.2 / 3.0.4 | 0.08 ms | 0.66 ms | 
| C (gcc) | 7.2.0 | 0.26 ms | 2.19 ms | 
| Shell (dash) | 0.5.8 | 0.33 ms | 2.81 ms | 
| Go (go) | 1.8.3 / 1.9.3 | 0.41 ms | 4.10 ms | 
| Rust (rustc) | 1.21.0 / 1.22.1 | 0.51 ms | 4.42 ms | 
| D (gdc) | 7.2.0 | 0.57 ms |  | 
| Lua | 5.2.4 | 0.63 ms | 6.23 ms | 
| Bash | 4.4.12(1) | 0.71 ms | 7.31 ms | 
| C++ (g++) | 7.2.0 | 0.79 ms | 8.24 ms | 
| Perl | 5.26.0 / 5.26.1 | 0.94 ms | 8.78 ms | 
| Haskell (ghc) | 8.0.2 | 0.72 ms | 9.44 ms | 
| ZShell | 5.2 / 5.4.2 | 1.57 ms | 11.04 ms | 
| CShell | 20110502 | 3.26 ms | 10.98 ms | 
| Python (with -S) | 2.7.14 | 2.91 ms | 32.77 ms | 
| Python | 2.7.14 | 9.43 ms | 91.85 ms | 
| PHP | 7.1.11 / 7.2.2 | 8.71 ms | 98.03 ms | 
| Cython | 0.25.2 / 0.26.1 | 9.91 ms | 98.71 ms | 
| Python3 (with -S) | 3.6.3 / 3.6.4 | 9.31 ms | 110.02 ms | 
| C# (mcs) | 4.6.2.0 | 13.37 ms | 137.53 ms | 
| PyPy | 5.8.0 | 27.53 ms | 183.50 ms | 
| Cython3 | 0.25.2 / 0.26.1 | 26.04 ms | 196.36 ms | 
| Python3 | 3.6.3 / 3.6.4 | 25.84 ms | 197.79 ms | 
| Ruby | 2.3.3p222 / 2.3.6p384 | 32.43 ms | 421.53 ms | 
| Java (javac) | 1.8.0_151 | 54.55 ms | 566.66 ms | 
| Go (gccgo) | 7.2.0 | 98.26 ms | 898.30 ms | 
| Scala (scalac) | 2.11.8 | 310.81 ms | 2989.72 ms | 
我们稍稍给这些结果分一下类,分为快速、普通、较慢、很慢。
如果在 Intel Core i5 2400S 的启动时间低于 1 ms,在 Raspberry Pi 3 的启动时间低于 10 ms,我们就认为这类编程语言的启动速度是快速,其中包括 Bash、C、C++、D (gdc)、Go (go)、Haskell、Lua、Pascal、Perl、Rust 和 Shell (dash)。
如果在 Intel Core i5 2400S 的启动时间介于 1 ms 到 5 ms 之间,在 Raspberry Pi 3 的启动时间介于 10 ms 到 50 ms 之间,那么我们就认为这类编程语言的启动速度是普通,其中包括 CShell、Python 2 (with -S)和 ZShell。
如果在 Intel Core i5 2400S 的启动时间介于 5 ms 到 50 ms 之间,在 Raspberry Pi 3 的启动时间介于 50 ms 到 500 ms 之间,那么我们就认为这类编程语言的启动速度是较慢,其中包括 C# (mcs)、Cython (Python 2)、Cython3 (Python 3)、PHP、Python 2、Python 3、Python 3 (with -S)、PyPy (Python 2)和 Ruby。
如果在 Intel Core i5 2400S 的启动时间超过 50ms,在 Raspberry Pi 3 的启动时间超过 500ms,我们就认为这类编程语言启动速度特别慢,其中包括 Java、Go (gccgo)和 Scala。
从关键字的多少来看编程语言的复杂性,C#的关键字最多(77 个)
想要使用编程语言就避不开关键字,编程语言中关键字的数量在一定程度上可以表明编程语言的复杂性,甚至还会影响到开发者利用该编程语言创造的相应程序的复杂性,而复杂的程序维护成本更高,招聘难度也会升级。
编程语言关键字的统计最早是由 @leighmcculloch 开始做的,下图是他的统计结果。
之后,GitHub 上的开发者 e3b0c442 对这个话题也非常感兴趣,所以他也做了一个相似的统计,下面我们就来看一下他的统计结果吧。
编程语言的具体关键字情况如下:
C (ANSI) (32 keywords)
http://port70.net/~nsz/c/c89/c89-draft.html#3.1.1
| auto | break | case | char | 
|---|
| const | continue | default | do | 
| double | else | enum | extern | 
| float | for | goto | if | 
| int | long | register | return | 
| short | signed | sizeof | static | 
| struct | switch | typedef | union | 
| unsigned | void | volatile | while | 
C (C18) (44 keywords)
http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf
| auto | break | case | char | 
|---|
| const | continue | default | do | 
| double | else | enum | extern | 
| float | for | goto | if | 
| inline | int | long | register | 
| restrict | return | short | signed | 
| sizeof | static | struct | switch | 
| typedef | union | unsigned | void | 
| volatile | while | _Alignas | _Alignof | 
| _Atomic | _Bool | _Complex | _Generic | 
| _Imaginary | _Noreturn | _Static_assert | _Thread_local | 
C# (5.0) (77 keywords)
https://download.microsoft.com/download/0/B/D/0BDA894F-2CCD-4C2C-B5A7-4EB1171962E5/CSharp%20Language%20Specification.docx
| abstract | as | base | bool | 
|---|
| break | byte | case | catch | 
| char | checked | class | const | 
| continue | decimal | default | delegate | 
| do | double | else | enum | 
| event | explicit | extern | false | 
| finally | fixed | float | for | 
| foreach | goto | if | implicit | 
| in | int | interface | internal | 
| is | lock | long | namespace | 
| new | null | object | operator | 
| out | override | params | private | 
| protected | public | readonly | ref | 
| return | sbyte | sealed | short | 
| sizeof | stackalloc | static | string | 
| struct | switch | this | throw | 
| true | try | typeof | uint | 
| ulong | unchecked | unsafe | ushort | 
| using | virtual | void | volatile | 
| while |  |  |  | 
C++ (C++17) (73 keywords)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf
| alignas | alignof | asm | auto | 
|---|
| bool | break | case | catch | 
| char | char16_t | char32_t | class | 
| const | constexpr | const_cast | continue | 
| decltype | default | delete | do | 
| double | dynamic_cast | else | enum | 
| explicit | export | extern | false | 
| float | for | friend | goto | 
| if | inline | int | long | 
| mutable | namespace | new | noexcept | 
| nullptr | operator | private | protected | 
| public | register | reinterpret_cast | return | 
| short | signed | sizeof | static | 
| static_assert | static_cast | struct | switch | 
| template | this | thread_local | throw | 
| true | try | typedef | typeid | 
| typename | union | unsigned | using | 
| virtual | void | volatile | wchar_t | 
| while |  |  |  | 
Dart (1) (33 keywords)
http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf
| assert | break | case | catch | 
|---|
| class | const | continue | default | 
| do | else | enum | extends | 
| false | final | finally | for | 
| if | in | is | new | 
| null | rethrow | return | super | 
| switch | this | throw | true | 
| try | var | void | while | 
| with |  |  |  | 
Elixir (1.7) (15 keywords)
https://github.com/elixir-lang/elixir/blob/master/lib/elixir/pages/Syntax%20Reference.md
| true | false | nil | when | 
|---|
| and | or | not | in | 
| fn | do | end | catch | 
| rescue | after | else |  | 
Erlang (21.2) (27 keywords)
http://erlang.org/doc/reference_manual/introduction.html#reserved-words
| after | and | andalso | band | 
|---|
| begin | bnot | bor | bsl | 
| bsr | bxor | case | catch | 
| cond | div | end | fun | 
| if | let | not | of | 
| or | orelse | receive | rem | 
| try | when | xor |  | 
Go (1.11) (25 keywords)
https://golang.org/ref/spec#Keywords
| break | case | chan | const | 
|---|
| continue | default | defer | else | 
| fallthrough | for | func | go | 
| goto | if | import | interface | 
| map | package | range | return | 
| select | struct | switch | type | 
| var |  |  |  | 
JS (ES2018) (34 keywords)
https://www.ecma-international.org/ecma-262/9.0/index.html#sec-keywords
| await | break | case | catch | 
|---|
| class | const | continue | debugger | 
| default | delete | do | else | 
| export | extends | finally | for | 
| function | if | import | in | 
| instanceof | new | return | super | 
| switch | this | throw | try | 
| typeof | var | void | while | 
| with | yield |  |  | 
Java (SE 11) (51 keywords)
https://docs.oracle.com/javase/specs/jls/se11/html/jls-3.html#jls-3.9
| abstract | assert | boolean | break | 
|---|
| byte | case | catch | char | 
| class | const | continue | default | 
| do | double | else | enum | 
| extends | final | finally | float | 
| for | if | goto | implements | 
| import | instanceof | int | interface | 
| long | native | new | package | 
| private | protected | public | return | 
| short | static | strictfp | super | 
| switch | synchronized | this | throw | 
| throws | transient | try | void | 
| volatile | while |  |  | 
Kotlin (1.3) (30 keywords)
https://kotlinlang.org/docs/reference/keyword-reference.html
| as | as? | break | class | 
|---|
| continue | do | else | false | 
| for | fun | if | in | 
 | interface | is |  | 
| null | object | package | return | 
| super | this | throw | true | 
| try | typealias | val | var | 
| when | while |  |  | 
PHP (7.0) (67 keywords)
http://php.net/manual/en/reserved.keywords.php
| __halt_compiler() | abstract | and | array() | 
|---|
| as | break | callable | case | 
| catch | class | clone | const | 
| continue | declare | default | die() | 
| do | echo | else | elseif | 
| empty() | enddeclare | endfor | endforeach | 
| endif | endswitch | endwhile | eval() | 
| exit() | extends | final | finally | 
| for | foreach | function | global | 
| goto | if | implements | include | 
| include_once | instanceof | insteadof | interface | 
| isset() | list() | namespace | new | 
| or | print | private | protected | 
| public | require | require_once | return | 
| static | switch | throw | trait | 
| try | unset() | use | var | 
| while | xor | yield |  | 
Python (2.7) (31 keywords)
https://docs.python.org/2/reference/lexical_analysis.html#keywords
| and | as | assert | break | 
|---|
| class | continue | def | del | 
| elif | else | except | exec | 
| finally | for | from | global | 
| if | import | in | is | 
| lambda | not | or | pass | 
| print | raise | return | try | 
| while | with | yield |  | 
Python (3.7) (35 keywords)
https://docs.python.org/3.7/reference/lexical_analysis.html#keywords
| False | None | True | and | 
|---|
| as | assert | async | await | 
| break | class | continue | def | 
| del | elif | else | except | 
| finally | for | from | global | 
| if | import | in | is | 
| lambda | nonlocal | not | or | 
| pass | raise | return | try | 
| while | with | yield |  | 
R (3.5) (20 keywords)
https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Reserved-words
| … | FALSE | Inf | NA | 
|---|
| NA_character_ | NA_complex_ | NA_integer_ | NA_real_ | 
| NaN | NULL | TRUE | break | 
| else | for | function | if | 
| in | next | repeat | while | 
Ruby (2.5) (41 keywords)
https://docs.ruby-lang.org/en/2.5.0/keywords_rdoc.html
| ENCODING | LINE | FILE | BEGIN | 
|---|
| END | alias | and | begin | 
| break | case | class | def | 
| defined? | do | else | elsif | 
| end | ensure | false | for | 
| if | in | module | next | 
| nil | not | or | redo | 
| rescue | retry | return | self | 
| super | then | true | undef | 
| unless | until | when | while | 
| yield |  |  |  | 
Rust (1.31) (53 keywords)
https://doc.rust-lang.org/grammar.html#keywords
| _ | abstract | alignof | as | 
|---|
| become | box | break | const | 
| continue | crate | do | else | 
| enum | extern | false | final | 
| fn | for | if | impl | 
| in | let | loop | macro | 
| match | mod | move | mut | 
| offsetof | override | priv | proc | 
| pub | pure | ref | return | 
| Self | self | sizeof | static | 
| struct | super | trait | true | 
| type | typeof | unsafe | unsized | 
| use | virtual | where | while | 
| yield |  |  |  | 
Scala (2.12) (40 keywords)
https://scala-lang.org/files/archive/spec/2.12/01-lexical-syntax.html
| abstract | case | catch | class | 
|---|
| def | do | else | extends | 
| false | final | finally | for | 
| forSome | if | implicit | import | 
| lazy | macro | match | new | 
| null | object | override | package | 
| private | protected | return | sealed | 
| super | this | throw | trait | 
| try | true | type | val | 
| var | while | with | yield | 
Swift (4.2) (70 keywords)
https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html
| associatedtype | class | deinit | enum | 
|---|
| extension | fileprivate | func | import | 
| init | inout | internal | let | 
| open | operator | private | protocol | 
| public | static | struct | subscript | 
| typealias | var | break | case | 
| continue | default | defer | do | 
| else | fallthrough | for | guard | 
| if | in | repeat | return | 
| switch | where | while | as | 
| Any | catch | false | is | 
| nil | rethrows | super | self | 
| Self | throw | throws | true | 
| try | _ | #available | #colorLiteral | 
| #column | #else | #elseif | #endif | 
| #error | #file | #fileLiteral | #function | 
| #if | #imageLiteral | #line | #selector | 
| #sourceLocation | #warning |  |  | 
编程语言与关键字个数对比表:
| 编程语言 | 关键字个数 | 
|---|
| C(ANSI) | 32 | 
| C(C18) | 44 | 
| C#(5.0) | 77 | 
| C ++(C ++ 17) | 73 | 
| Dart(1) | 33 | 
| Elixir(1.7) | 15 | 
| Erlang(21.2) | 27 | 
| Go(1.11) | 25 | 
| JS(ES2018) | 34 | 
| Java(SE 11) | 51 | 
| Kotlin(1.3) | 30 | 
| PHP(7.0) | 67 | 
| Python(2.7) | 31 | 
| Python(3.7) | 35 | 
| R(3.5) | 20 | 
| Ruby(2.5) | 41 | 
| Rust(1.31) | 53 | 
| Scala(2.12) | 40 | 
| Swift(4.2) | 70 | 
总体来看,编程语言的关键字都集中在两位数,关键字个数在 50 以上的共有 6 个,其中最多的是 C#,共有 77 个关键字;关键字个数在 30-50 之间的编程语言共有 9 个;关键字个数低于 30 的编程语言有 4 个,其中最少的是 Elixir,只有 15 个关键字。
参考链接:
https://github.com/bdrung/startup-time
https://github.com/e3b0c442/keywords
评论 2 条评论