-
-
Save nazariyv/c6a8e3b8c4b57d6f9469feeb9a7f3fd0 to your computer and use it in GitHub Desktop.
Python timeit benchmarking for realistic optimizations.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# All units in usecs (µsec) comparing Python 2.7 | 3.7. | |
# Last updated: 2019-02-11 | |
# MacBook Pro (15-inch, 2016) | |
# macOS 10.14.3 | |
# 2.7 GHz Intel Core i7 | |
# 16 GB 2133 MHz LPDDR3 | |
python -m timeit "200 <= 250 < 300" # 0.0354 | 0.059 | |
python2.7 -m timeit "250 in xrange(200, 300)" # 1.25 | |
python3.7 -m timeit "250 in range(200, 300)" # 0.324 -- yay for __contains__! | |
python -m timeit 's="Content-Type: text/html\r\n"' 'a,b = s.split(":", 1)' # 0.305 | 0.249 | |
python -m timeit 's="Content-Type: text/html\r\n"' 'a,b = s.split(":")' # 0.287 | 0.285 | |
python -m timeit 's="Content-Type: text/html\r\n"' 'a,c = s.partition(":")[::2]' # 0.22 | 0.275 | |
python -m timeit 's="Content-Type: text/html\r\n"' 'a,b,c = s.partition(":")' # 0.13 | 0.189 ! | |
# Partition is faster, despite the extra variable assignment. | |
python -m timeit 's="Content-Type: text/html\r\n"' 's.upper()' # 0.348 | 0.121 | |
python -m timeit 's="CONTENT-TYPE: text/html\r\n"' 's.upper()' # 0.307 | 0.106 ! | |
python -m timeit 's="CONTENT-TYPE: TEXT/HTML\r\n"' 's.upper()' # 0.270 | 0.101 ! | |
python -m timeit 's="Content-Type: text/html\r\n"' 's.title()' # 0.344 | 0.340 | |
python -m timeit 's="Content-Type: text/html\r\n"' 's.lower()' # 0.274 | 0.102 ! | |
# If you need to case-insensitively compare strings that are mostly lower-case, lower-case them. | |
python -m timeit 'a="foo";b="bar"' '", ".join((a, b))' # 0.136 | 0.158 | |
python -m timeit 'a="foo";b="bar"' 'a + ", " + b' # 0.0668 | 0.135 ! | |
# Join might be fancy for small lists or tuples, but it's a horrible waste of resources. | |
python -m timeit 'a="foo.bz"' 'a.endswith("bz")' # 0.164 | 0.157 | |
python -m timeit 'a="foo.bz"' 'a[-2:] == "bz"' # 0.0676 | 0.132 ! | |
# Slicing is fast, no, faster than that. | |
python -m timeit 'line="GET / HTTP/1.1"' 'a,b,c = line.split(" ", 2)' # 0.304 | 0.274 | |
python -m timeit 'line="GET / HTTP/1.1"' 'a,_,_ = line.partition(" "); b,_,c = _.partition(" ")' # 0.226 | 0.307 ! | |
python -m timeit 'line="GET / HTTP/1.1"' 'a,b,c = line.split(" ")' # 0.295 | 0.228 ! | |
# Splitting is strange; how can limiting the split take -longer- than so much variable assignment? | |
python2.7 -m timeit 'from urllib import unquote; import re; qs = re.compile("(?i)%2F"); path = "/foo%2Fbar/bar/baz"' '[unquote(x) for x in qs.split(path)]' # 4.33 | |
python3.7 -m timeit 'from urllib.parse import unquote; import re; qs = re.compile("(?i)%2F"); path = "/foo%2Fbar/bar/baz"' '[unquote(x) for x in qs.split(path)]' # 3.26 | |
python2.7 -m timeit 'from urllib import unquote; import re; path = "/foo%2Fbar/bar/baz"' 'path.replace("%2F", "\0").replace("%2f", "\0"); path = unquote(path); path.replace("\0", "%2F")' # 3.69 | |
python3.7 -m timeit 'from urllib.parse import unquote; import re; path = "/foo%2Fbar/bar/baz"' 'path.replace("%2F", "\0").replace("%2f", "\0"); path = unquote(path); path.replace("\0", "%2F")' # 5.79 | |
# The decoding of URLs has some interesting requirements. Using regular expressions may be easy... but not fast. | |
python -m timeit 'line=""' 'line.split(",")' # 0.220 | 0.129 | |
python -m timeit 'line=None' 'if line: line.split(",")' # 0.0192 | 0.0193 ! | |
# It is better to test for a value before splitting, rather than splitting empty strings. | |
python -m timeit 'a="://"; b="http://www.example.com/"' 'a in b' # 0.0404 | 0.0484 | |
python -m timeit 'a="://"; b="http://www.example.com/"' 'b.find(a)' # 0.186 | 0.167 | |
python -m timeit 'a="://"; b="/foo/bar/baz"' 'a in b' # 0.0401 | 0.0505 | |
python -m timeit 'a="://"; b="/foo/bar/baz"' 'b.find(a)' # 0.191 | 0.176 | |
# In is faster, but doesn't return the offset. | |
python -m timeit 'uri="/foo/bar/baz"' 'uri.startswith("/")' # 0.174 | 0.174 | |
python3.7 -m timeit 'uri="/foo/bar/baz"' 'uri[0] == "/"' # 0.0467 | 0.0555 | |
python3.7 -m timeit 'uri="foo/bar/baz"' 'uri.startswith("/")' # 0.170 | 0.154 | |
python3.7 -m timeit 'uri="foo/bar/baz"' 'uri[0] == "/"' # 0.0468 | 0.0597 | |
# Array slicing from the beginning is much faster than str.startswith. | |
python -m timeit 'a=(1,2,3,4,5,6,7,8,9,0)' 'a[-5:][::-1]' # 0.146 | 0.192 | |
python -m timeit 'a=(1,2,3,4,5,6,7,8,9,0)' 'a[::-1][:5]' # 0.167 | 0.185 | |
python -m timeit 'a=(1,2,3,4,5,6,7,8,9,0)' 'a[:4:-1]' # 0.103 | 0.107 ! | |
# Performing a single slice is faster than slicing broken apart, but... | |
# reversing a smaller slice is faster than reversing a large one. (Duh. ;) | |
import time | |
import datetime | |
then = 951196249 | |
now = 1551196249 | |
%timeit (now - then) > 0.5 | |
# 117 ns ± 4.24 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) | |
%timeit (datetime.datetime.fromtimestamp(now) - datetime.datetime.fromtimestamp(then)) > datetime.timedelta(seconds=0.5) | |
# 2.4 µs ± 208 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment