(点击
上方蓝字
,快速关注我们)
译文:伯乐在线 - 艾凌风
英文:computers-are-fast.github.io
如有好文章投稿,请点击 → 这里了解详情
如需转载,发送「转载」二字查看说明
让我们看看你有多了解你的电脑!所有这些程序里都包含一个 NUMBER 变量。你的任务是:猜猜需要把 NUMBER 设置为一个多大的数,才能让相应的程序执行耗时一秒。
你不需要猜出准确数字:它们都介于1到十亿之间。猜出数量级即可!注意以下几点:
-
如果正确答案是 38,000,那么猜 10,000 和 100,000 都是正确的。
-
我们知道,计算机有着不同的硬盘性能、网速和CPU速度!我们试图让你能够区分运行 10次/秒 和 10万次/秒 的代码之间的差别。一台新的电脑并不能让你的代码运行速度快上1000倍 :)
-
也就是说,所有的代码运行在一台新款笔记本电脑上,它有着快速的SSD硬盘以及还不错的网速。C 代码全部使用 gcc -O2 来进行编译
祝你好运!很多问题的答案会出乎你的意料。我们会匿名收集你的答案,未来我们公布一些图表哦,敬请期待! =D
欢迎来到第一个问题!这个问题是让你练练手:
在一秒中之内能执行多少次循环?(可能比你想象的要多得多哦!)
猜猜看:1 秒钟执行循环次数
#include
// 猜数字: 在1秒钟时间内
// 这个循环可以执行多少次
int
main
(
int
argc
,
char
**
argv
)
{
int
NUMBER
,
i
,
s
;
NUMBER
=
atoi
(
argv
[
1
]);
for
(
s
=
i
=
0
;
i
NUMBER
;
++
i
)
{
s
+=
1
;
}
return
0
;
}
准确答案:550,000,000
猜猜看:1秒钟执行循环次数
#!/usr/bin/env python
# 猜数字: 一秒钟内可以执行
# 多少次空循环
def
f
(
NUMBER
)
:
for
_
in
xrange
(
NUMBER
)
:
pass
import
sys
f
(
int
(
sys
.
argv
[
1
]))
准确答案:68,000,000
既然我们已经知道了 Python 的极限(1亿 指令/秒),让我们看一个更加实际的例子。字典在Python中的应用随处可见,所以,在一秒钟的时间里,我们能够向一个字典添加多少元素呢?
猜猜看:1秒钟执行循环次数
#!/usr/bin/env python
# 猜数字: 在一秒钟内,我们能向
# 字典添加多少个条目?
# 注意: 我们使用 `i % 1000`
# 来控制字典的大小
def
f
(
NUMBER
)
:
d
=
{}
for
i
in
xrange
(
NUMBER
)
:
d
[
i
%
1000
]
=
i
import
sys
f
(
int
(
sys
.
argv
[
1
]))
准确答案:11,000,000
当你搞定这题之后,让我们看一个更复杂的操作,用 Python 内建的 HTTP 请求解析器来解析一个请求
猜猜看:1秒钟可以解析的HTTP请求数
#!/usr/bin/env python
# 猜数字: 一秒钟可以解析多少HTTP请求
from
BaseHTTPServer
import
BaseHTTPRequestHandler
from
StringIO
import
StringIO
class
HTTPRequest
(
BaseHTTPRequestHandler
)
:
def
__init__
(
self
,
request_text
)
:
self
.
rfile
=
StringIO
(
request_text
)
self
.
raw_requestline
=
self
.
rfile
.
readline
()
self
.
error_code
=
self
.
error_message
=
None
self
.
parse_request
()
def
send_error
(
self
,
code
,
message
)
:
self
.
error_code
=
code
self
.
error_message
=
message
request_text
=
"""GET / HTTP/1.1
Host: localhost:8001
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
"""
def
f
(
NUMBER
)
:
for
_
in
range
(
NUMBER
)
:
HTTPRequest
(
request_text
)
import
sys
f
(
int
(
sys
.
argv
[
1
]))
接下来,我们将会看到,下载一个网页 vs 执行一个 Python 脚本!
提示:本题答案都小于1亿 :)
猜猜看:1秒钟可以完成的HTTP请求数
#!/usr/bin/env python
# 猜数字: 一秒钟的时间,我们可以从
# google.com 下载多少页面?
from
urllib2
import
urlopen
def
f
(
NUMBER
)
:
for
_
in
xrange
(
NUMBER
)
:
r
=
urlopen
(
"http://google.com"
)
r
.
read
()
import
sys
f
(
int
(
sys
.
argv
[
1
]))
准确答案:4
猜猜看:1秒钟执行循环次数
#!/bin/bash
# 猜数字: 在一秒内,我们可以启动多少次
# Python解释器?
NUMBER
=
$
1
for
i
in
$(
seq
$NUMBER
);
do
python
-
c
''
;
done
准确答案:77
启动程序本身就非常耗时,并不只有是Python是这样。如果我们只是运行/bin/true,那么1秒能做500次,所以看起来运行任何程序一般需要大约1毫秒时间。当然,下载网页的快慢很大程度上取决于网页大小、网络连接速度、以及服务器间的距离,今天我们并不会深入探讨网络性能(网络性能是一件非常有趣的事情)。一个从事高性能网络开发的朋友告诉我,一次网络往返可以做到250ns(!!!),但是要求计算机距离非常近,同时搭配豪华的硬件配置。对我们和Google来讲,耗时是它的一百万倍。在一个纳秒的时间,光只能传播一英尺,而谷歌的服务器远在250英尺以外的地方。
在一秒钟时间内,可以向硬盘写多少字节的数据?我们都知道向内存写数据更快些,但是快多少呢?下面的代码在一个装有SSD的硬盘上执行。
猜猜看:一秒钟写入多少字节
#!/usr/bin/env python
# 猜数字: 一秒的时间我们可以向一个文件写入
# 多少byt字节?
# 注意:我们确保所有数据在退出前都已经同步到硬盘
import
tempfile
import
os
CHUNK_SIZE
=
1000000
s
=
"a"
*
CHUNK_SIZE
def
cleanup
(
f
,
name
)
:
f
.
flush
()
os
.
fsync
(
f
.
fileno
())
f
.
close
()
try
:
os
.
remove
(
name
)
except
:
pass
def
f
(
NUMBER
)
:
name
=
'./out'
f
=
open
(
name
,
'w'
)
bytes_written
=
0
while
bytes_written
NUMBER
:
f
.
write
(
s
)
bytes_written
+=
CHUNK_SIZE
cleanup
(
f
,
name
)
import
sys
f
(
int
(
sys
.
argv
[
1
]))
准确答案:342,000,000
猜猜看:一秒钟写入多少字节
#!/usr/bin/env python
# 猜数字: 在一秒钟内,我们能够向一个
# 内存中的字符串写入多少字节
import
cStringIO
CHUNK_SIZE
=
1000000
s
=
"a"
*
CHUNK_SIZE
def
f
(
NUMBER
)
:
output
=
cStringIO
.
StringIO
()
bytes_written
=
0
while
bytes_written
NUMBER
:
output
.
write
(
s
)
bytes_written
+=
CHUNK_SIZE
import
sys
f
(
int
(
sys
.
argv
[
1
]))
准确答案:2,000,000,000
硬盘比内存要慢,即使你使用“较慢”的语言,比如Python,这种差别也是有影响的。如果你使用一个非常快速的硬盘(我的SSD已知的写入速度>500MB/s,可以称得上快)很多事情最终都受限于硬盘的速度。我们来看下一个例子!
文件时间到!有时候我执行一条 grep 命令处理大量数据,然后它就一直执行下去了,grep 在一秒内可以搜索多少字节的数据呢?
注意,当程序执行时,grep读入的数据已经全部读入内存。这让我们能够知道grep慢的原因,多少是因为搜索,多少是因为读取到硬盘。
列出文件同样耗时!在一秒钟内可以列出多少文件呢?
猜猜看:1秒能够搜索多少字节?
#!/bin/bash
# 猜数字: `grep`命令1秒能够搜索多少字节
# 注意: 数据已经在内存中
NUMBER
=
$
1
cat
/
dev
/
zero
|
head
-
c
$NUMBER
|
grep
blah
exit
0
准确答案:2,000,000,000
猜猜看:一秒能够列出多少文件?
#!/bin/bash
# Number to guess: `find`命令 一秒钟能够列出多少文件?
# 注意: 文件在文件系统缓存中。
find
/ -
name
'*'
2
> /
dev
/
null
|
head
-
n
$
1
> /
dev
/
null
准确答案:325,000
很好!现在我知道grep可以以2GB/s的速度搜索,所以,至少在这个例子中,我们程序的速度主要受限于硬盘速度而不是grep的速度。
序列化通常是一个很耗时的工作,尤其是当你需要反复的序列化/反序列化一份数据的时候,真的非常痛苦。这里有一些基准测试:解析 64K 的JSON文件,同样的数据用 msgpack 格式编码。
猜猜看:一秒钟循环次数
#!/usr/bin/env python
# 猜数字: 在一秒钟内,我们能够解析一个
# 64K 的 JSON 文件多少次?
import
json
with