你知道你的电脑 1 秒钟能做多少事情吗?-阿里云开发者社区

开发者社区> 开发与运维> 正文
登录阅读全文

你知道你的电脑 1 秒钟能做多少事情吗?

简介:

让我们来看看你有多么了解电脑!所有这些程序的数值都是可变的。你的任务是:在程序花费1秒运行之前猜测它的大概值。

你并不需要猜出一个精确值:选择范围在1和10亿之间。你只要能猜出正确的数量级,就算正确!下面是一些注意事项:

  • 如果答案是38,000,那么你选择10,000或100,000,我们就认为都是正确答案。误差只要在10倍范围内就ok:)

  • 我们知道不同的计算机有不同的磁盘、网络和CPU速度!我们会告诉运行10次/秒和10万次/秒的代码之间的差别。更新的电脑不会让你的代码运行速度快1000倍:)

  • 也就是说,所有这一切都是运行在一台新的拥有一个快速的SSD和一个凑合的网络连接的笔记本电脑上的。 C代码用gcc -O2编译。

祝你好运!

欢迎来到第一个程序!这一个只是让你练练手的:1秒能完成多少循环? (结果可能比你想象得更多!)

猜猜下面的程序每秒执行多少次循环:


  1. #include <stdlib.h> 
  2.  
  3. // Number to guess: How many iterations of 
  4. // this loop can we go through in a second? 
  5.  
  6. int main(int argc, char **argv) { 
  7.     int NUMBER, i, s; 
  8.     NUMBER = atoi(argv[1]); 
  9.  
  10.     for (s = i = 0; i < NUMBER; ++i) { 
  11.         s += 1
  12.     } 
  13.  
  14.     return 0

准确答案:550,000,000

猜猜下面的程序每秒执行多少次循环:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many iterations of an 
  4. # empty loop can we go through in a second? 
  5.  
  6. def f(NUMBER): 
  7.     for _ in xrange(NUMBER): 
  8.         pass 
  9.  
  10. import sys 
  11. f(int(sys.argv[1])) 

当我看着代码的时候,我想的是1毫秒完成多少次——我以为是微不足道的,但事实是,即使是Python,你也可以在1毫秒的时间内执行68,000次空循环迭代。

下面让我们来探讨一个更接近现实的用例。在Python中字典几乎是无处不在的,那么在1秒时间内我们可以用Python添加多少元素呢?
然后再来看一个更复杂的操作——使用Python的内置HTTP请求解析器来解析请求。

猜猜下面的程序每秒执行多少次循环:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many entries can 
  4. # we add to a dictionary in a second? 
  5.  
  6. # Note: we take `i % 1000` to control 
  7. # the size of the dictionary 
  8.  
  9. def f(NUMBER): 
  10.     d = {} 
  11.     for i in xrange(NUMBER): 
  12.         d[i % 1000] = i 
  13.  
  14. import sys 
  15. f(int(sys.argv[1])) 
  16.  
  17. 准确答案:11,000,000 

猜猜下面的程序每秒处理多少次HTTP请求:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many HTTP requests 
  4. # can we parse in a second? 
  5.  
  6. from BaseHTTPServer import BaseHTTPRequestHandler 
  7. from StringIO import StringIO 
  8.  
  9. class HTTPRequest(BaseHTTPRequestHandler): 
  10.     def __init__(self, request_text): 
  11.         self.rfile = StringIO(request_text) 
  12.         self.raw_requestline = self.rfile.readline() 
  13.         self.error_code = self.error_message = None 
  14.         self.parse_request() 
  15.  
  16.     def send_error(self, code, message): 
  17.         self.error_code = code 
  18.         self.error_message = message 
  19.  
  20. request_text = """GET / HTTP/1.1 
  21. Host: localhost:8001 
  22. Connection: keep-alive 
  23. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 
  24. Upgrade-Insecure-Requests: 1 
  25. 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 
  26. Accept-Encoding: gzip, deflate, sdch 
  27. Accept-Language: en-GB,en-US;q=0.8,en;q=0.6 
  28. ""
  29.  
  30. def f(NUMBER): 
  31.     for _ in range(NUMBER): 
  32.         HTTPRequest(request_text) 
  33.  
  34. import sys 
  35. f(int(sys.argv[1])) 
  36.  
  37. 准确答案:25,000 

我们每秒可以解析25,000个小的HTTP请求!有一件事我要在这里指出的是,这里请求解析的代码是用纯Python编写的,而不是C。

接下来,我们要试试下载网页与运行Python脚本!提示:少于1亿:)

猜猜下面的程序每秒可以完成多少次HTTP请求:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many times can we 
  4. # download google.com in a second? 
  5.  
  6. from urllib2 import urlopen 
  7.  
  8. def f(NUMBER): 
  9.     for _ in xrange(NUMBER): 
  10.         r = urlopen("http://google.com"
  11.         r.read() 
  12.  
  13. import sys 
  14. f(int(sys.argv[1])) 

准确答案:4

猜猜下面的程序每秒可以执行多少次循环:


  1. #!/bin/bash 
  2.  
  3. # Number to guess: How many times can we start 
  4. # the Python interpreter in a second? 
  5.  
  6. NUMBER=$1 
  7.  
  8. for i in $(seq $NUMBER); do 
  9.     python -c ''
  10. done 

准确答案:77

启动程序实际上昂贵在其本身,而不是启动Python。如果我们只是运行/bin/true,那么1秒能做500次,所以看起来运行任何程序只需要 大约1毫秒时间。当然,下载网页的快慢很大程度上取决于网页大小,网络连接速度,以及服务器间的距离,不过今天我们不谈网络性能。我的一个朋友说,高性能 的网络完成网络往返甚至可能只要250纳秒(!!!),但这是在计算机位置更相邻,硬件更好的情况下。

1秒时间能够在磁盘中写入多少字节?我们都知道写到内存中时速度会更快,但是究竟会快多少呢?对了,下面的代码运行在带有SSD的计算机上。

猜猜下面的程序每秒可以写入多少字节数据:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many bytes can we write 
  4. # to an output file in a second? 
  5. # Note: we make sure everything is sync'd to disk 
  6. # before exiting 
  7. import tempfile 
  8. import os 
  9.  
  10. CHUNK_SIZE = 1000000 
  11. s = "a" * CHUNK_SIZE 
  12.  
  13. def cleanup(f, name): 
  14.     f.flush() 
  15.     os.fsync(f.fileno()) 
  16.     f.close() 
  17.     try
  18.         os.remove(name) 
  19.     except: 
  20.         pass 
  21.  
  22. def f(NUMBER): 
  23.     name = './out' 
  24.     f = open(name, 'w'
  25.     bytes_written = 0 
  26.     while bytes_written < NUMBER: 
  27.         f.write(s) 
  28.         bytes_written += CHUNK_SIZE 
  29.     cleanup(f, name) 
  30.  
  31. import sys 
  32. f(int(sys.argv[1])) 

准确答案:342,000,000

猜猜下面的程序每秒可以写入多少字节数据:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many bytes can we write 
  4. # to a string in memory in a second? 
  5.  
  6. import cStringIO 
  7.  
  8. CHUNK_SIZE = 1000000 
  9. s = "a" * CHUNK_SIZE 
  10.  
  11. def f(NUMBER): 
  12.     output = cStringIO.StringIO() 
  13.     bytes_written = 0 
  14.     while bytes_written < NUMBER: 
  15.         output.write(s) 
  16.         bytes_written += CHUNK_SIZE 
  17.  
  18. import sys 
  19. f(int(sys.argv[1])) 

准确答案:2,000,000,000

下面轮到文件了!有时候,运行一个大型的grep之后,它可以永恒跑下去。在1秒时间内,grep可以搜索多少字节?
请注意,在这么做的时候,grep正在读取的字节已经在内存中。
文件列表同样需要时间!1秒能列出多少文件?

猜猜下面的程序每秒可以搜索多少字节的数据:


  1. #!/bin/bash 
  2.  
  3. # Number to guess: How many bytes can `grep` 
  4. # search, unsuccessfully, in a second? 
  5. # Note: the bytes are in memory 
  6.  
  7. NUMBER=$1 
  8.  
  9. cat /dev/zero | head -c $NUMBER | grep blah 
  10. exit 0 
  11.  
  12. 准确答案:2,000,000,000 
  13.  
  14. 猜猜下面的程序每秒可以列出多少文件: 
  15.  
  16. #!/bin/bash 
  17.  
  18. # Number to guess: How many files can `find` list in a second? 
  19. # Note: the files will be in the filesystem cache. 
  20.  
  21. find / -name '*' 2> /dev/null | head -n $1 > /dev/null 

准确答案:325,000

序列化是一个普遍要花费大量时间的地方,让人很蛋疼,特别是如果你反复结束序列化/反序列化相同数据的时候。这里有几个基准:转换64K大小的JSON格式数据,与同样大小的msgpack格式数据。

猜猜下面的程序每秒可以执行多少次循环:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many times can we parse 
  4. # 64K of JSON in a second? 
  5.  
  6. import json 
  7.  
  8. with open('./setup/protobuf/message.json') as f: 
  9.     message = f.read() 
  10.  
  11. def f(NUMBER): 
  12.     for _ in xrange(NUMBER): 
  13.         json.loads(message) 
  14.  
  15. import sys 
  16. f(int(sys.argv[1])) 

准确答案:449

猜猜下面的程序每秒可以执行多少次循环:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many times can we parse 
  4. # 46K of msgpack data in a second? 
  5.  
  6. import msgpack 
  7.  
  8. with open('./setup/protobuf/message.msgpack') as f: 
  9.     message = f.read() 
  10.  
  11. def f(NUMBER): 
  12.     for _ in xrange(NUMBER): 
  13.         msgpack.unpackb(message) 
  14.  
  15. import sys 
  16. f(int(sys.argv[1])) 

准确答案:4,000

数据库。没有任何类似于PostgreSQL花里胡哨的东西,我们做了2份有1000万行数据的SQLite表,一个是有索引的,另一个是未建索引的。

猜猜下面的程序每秒可以执行多少次查询:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many times can we 
  4. # select a row from an **indexed** table with 
  5. 10,000,000 rows? 
  6.  
  7. import sqlite3 
  8.  
  9. conn = sqlite3.connect('./indexed_db.sqlite'
  10. c = conn.cursor() 
  11. def f(NUMBER): 
  12.     query = "select * from my_table where key = %d" % 5 
  13.     for i in xrange(NUMBER): 
  14.         c.execute(query) 
  15.         c.fetchall() 
  16.  
  17. import sys 
  18. f(int(sys.argv[1])) 

准确答案:53,000

猜猜下面的程序每秒执行多少次查询:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many times can we 
  4. # select a row from an **unindexed** table with 
  5. 10,000,000 rows? 
  6.  
  7. import sqlite3 
  8.  
  9. conn = sqlite3.connect('./unindexed_db.sqlite'
  10. c = conn.cursor() 
  11. def f(NUMBER): 
  12.     query = "select * from my_table where key = %d" % 5 
  13.     for i in xrange(NUMBER): 
  14.         c.execute(query) 
  15.         c.fetchall() 
  16.  
  17. import sys 
  18. f(int(sys.argv[1])) 

准确答案:2

下面要说Hash算法!在这里,我们将比较MD5和bcrypt。用MD5你在1秒时间内可以哈希到相当多的东西,而用bcrypt则不能。

猜猜下面的程序每秒可以哈希多少字节的数据:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many bytes can we md5sum in a second? 
  4.  
  5. import hashlib 
  6.  
  7. CHUNK_SIZE = 10000 
  8. s = 'a' * CHUNK_SIZE 
  9.  
  10. def f(NUMBER): 
  11.     bytes_hashed = 0 
  12.     h = hashlib.md5() 
  13.     while bytes_hashed < NUMBER: 
  14.         h.update(s) 
  15.         bytes_hashed += CHUNK_SIZE 
  16.     h.digest() 
  17. import sys 
  18. f(int(sys.argv[1])) 

准确答案:455,000,000

猜猜下面的程序每秒可以哈希多少字节的密码:


  1. #!/usr/bin/env python 
  2.  
  3. # Number to guess: How many passwords 
  4. # can we bcrypt in a second? 
  5.  
  6. import bcrypt 
  7.  
  8. password = 'a' * 100 
  9.  
  10. def f(NUMBER): 
  11.     for _ in xrange(NUMBER): 
  12.         bcrypt.hashpw(password, bcrypt.gensalt()) 
  13.  
  14. import sys 
  15. f(int(sys.argv[1])) 

准确答案:3

接下来,我们要说一说内存访问。 现在的CPU有L1和L2缓存,这比主内存访问速度更快。这意味着,循序访问内存通常比不按顺序访问内存能提供更快的代码。

猜猜下面的程序每秒可以向内存写入多少字节数据:


  1. #include <stdlib.h> 
  2. #include <stdio.h> 
  3.  
  4. // Number to guess: How big of an array (in bytes) 
  5. // can we allocate and fill in a second? 
  6.  
  7. // this is intentionally more complicated than it needs to be 
  8. // so that it matches the out-of-order version 
  9.  
  10. int main(int argc, char **argv) { 
  11.     int NUMBER, i; 
  12.     NUMBER = atoi(argv[1]); 
  13.  
  14.     char* array = malloc(NUMBER); 
  15.     int j = 1
  16.     for (i = 0; i < NUMBER; ++i) { 
  17.         j = j * 2
  18.         if (j > NUMBER) { 
  19.             j = j - NUMBER; 
  20.         } 
  21.         array[i] = j; 
  22.     } 
  23.  
  24.     printf("%d", array[NUMBER / 7]); 
  25.     // so that -O2 doesn't optimize out the loop 
  26.  
  27.     return 0

准确答案:376,000,000

猜猜下面的程序每秒可以向内存写入多少字节数据:


  1. #include <stdlib.h> 
  2. #include <stdio.h> 
  3.  
  4. // Number to guess: How big of an array (in bytes) 
  5. // can we allocate and fill with 5s in a second? 
  6. // The catch: We do it out of order instead of in order. 
  7. int main(int argc, char **argv) { 
  8.     int NUMBER, i; 
  9.     NUMBER = atoi(argv[1]); 
  10.  
  11.     char* array = malloc(NUMBER); 
  12.     int j = 1
  13.     for (i = 0; i < NUMBER; ++i) { 
  14.         j = j * 2
  15.         if (j > NUMBER) { 
  16.             j = j - NUMBER; 
  17.         } 
  18.         array[j] = j; 
  19.     } 
  20.  
  21.     printf("%d", array[NUMBER / 7]); 
  22.     // so that -O2 doesn't optimize out the loop 
  23.  
  24.     return 0

准确答案:68,000,000

欢迎大家去试一试,给我们留下宝贵的意见。



作者:小峰

来源:51CTO

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章
最新文章
相关文章