[英]How Long Do Programming Operations Take?
我们都可能从 Peter Norvigís 的文章《十年内自学编程》中看到这张表:
电脑动作 | 时间 [以纳秒为单位] |
---|---|
执行典型指令 | 1 |
从 L1 缓存 memory 获取 | 0.5 |
分支误判 | 5 |
从二级缓存 memory 获取 | 7 |
互斥锁/解锁 | 25 |
从主 memory 获取 | 100 |
通过 1Gbps 网络发送 2K 字节 | 20,000 |
从 memory 顺序读取 1MB | 250,000 |
从新磁盘位置获取 [seek] | 8,000,000 |
从磁盘顺序读取 1MB | 20,000,000 |
将数据包从美国发送到欧洲并返回 | 150,000,000 |
问题是,我不知道这在现实世界中意味着什么。
你看,现在所有最流行的语言都非常抽象,你基本上不需要自己接触一块 memory。 我只知道“我输入了东西,计算机 go brrrrr”,或者“我输入了东西,计算机 go [TASK NOT RESPONDING] 然后 Z34D1F91FB2E514B8566FABrr1A75A”。 当您只知道函数和库并且唯一可用的时序信息以位和字节为单位时,优化很难。
我将理解我最终编写的每一行代码的 memory 含义,但现在,我想知道的是:
像:
int foo = bar.getValue(); if (foo == 0 || foo == 1)...
int foo = bar.getValue(); if (foo == 0 || foo == 1)...
if (bar.getValue() == 0 || bar.getValue() == 1)...
我也对其他语言的含义感兴趣——也就是说,如果某些语言在某些任务上比其他语言更好。 例如,我知道与 Java 之类的语言相比,JS 中的数组操作很糟糕,而且我想在 lisp 之类的语言中更改函数会容易得多,那么在某些语言中哪些操作会比其他语言更有效?
谢谢!
一方面,数字是有问题的。 我会这样纠正:
其中的 rest 或多或少是正确的,尽管 SSD 将磁盘延迟提高了几个数量级。
现在回到你的问题。 有 3 组语言/运行时。
编译为本机代码,如 C++ 或 Golang。 通常但并非总是如此,这是可用的最快选项。
解释,像大多数 Lua 和 Python 实现。 解释器在设计上很慢,但是其中许多调用了许多本机函数。 对于这些东西,成本接近本机代码,没有用于间接跳转和编组 arguments / 返回值的少量开销。 例如,如果您编写并测试读取和操作大量字符串的 python 代码,则可以肯定 Python 运行时将调用本机代码,如果您使用内置方法操作它们,将会非常快。
及时编译,如 Java、.NET 或现代 JavaScript 实现。 这些变化很大。 最佳 C# 或 Java 实现接近本机代码的性能。 JavaScript 通常不会,因为该语言是动态类型的,并且很难从中生成快速代码。
读取和操作字符串
如果一个字符串需要 1MB,那么在你的表中读取它就是“从内存中顺序读取 1MB”。 操作会有所不同,具体取决于您对它们的确切操作。
创建基元
如果您的意思是定义一个局部变量,对于使用本机堆栈的语言(所有编译的,以及其他一些如 C#),成本是“执行典型指令”。 对于只使用堆的语言,成本是 malloc(),稍微贵一些。
比较两个原语
对于强类型语言“执行典型指令”,对于动态类型“间接跳转”。
比较两个对象
变化很大。 比较指针是“执行典型指令”。 比较值,取决于值,可能会非常昂贵。
迭代一个循环
事实上,对于大多数语言来说,这是典型的指令,但是其中一些有时可以在长循环中更快地做到这一点,使用自动矢量化或引擎盖下的并行化。
将控制权转移到(或“调用”)方法/函数
一方面,许多语言可以根据需要和可能的情况自动内联。 否则,function 或非虚拟方法的成本是一些典型的指令。 对于虚方法可以更多。 当预测时(您在循环中多次调用相同的虚拟方法,并且每次都解析到相同的代码位置)大致相同,当未预测“分支错误预测”的成本时
访问“列表”
无法回答,因为不同运行时库中的实现方式差异太大。 在 Java 或 C# 等语言中,列表由数组支持并共享性能特征。 如果您的意思是依赖于缓存的“链表”,在最好的情况下,每个元素“从 L1 缓存中获取”,在最坏的情况下,“从主内存中获取”每个被访问的元素。
初始化 object
取决于太多的事情。 在某些情况下甚至可以免费。
实例化 class 时,object 中包含的每个方法是否会导致运行时损失?
在大多数语言中,没有。 在非常动态类型的语言中可以是“是”,即使 Python 不够动态,JavaScript 可能是。
问题的 rest 过于依赖特定的语言/运行时。 也在你的代码上。 如果编译器可以推断出具体的实现,许多 C++ 编译器可能会去虚拟化方法调用。 如果您的getValue
方法只返回一个字段而不是计算事物,大多数编译器/运行时/解释器将内联调用,这两个版本将生成等效代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.