提到编程语言,大多数的文章内容都这样的: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 条评论