[Python-Dev] New stringbench benchmark results

Victor Stinner victor.stinner at haypocalc.com
Thu Oct 6 02:06:30 CEST 2011


Hi,

I optimized unicodeobject.c a little bit more where I saw major performance 
regressions from Python 3.2 to 3.3 using stringbench. Here are new results: 
see attachments. Example of tests where Python 3.3 is much slower:

"A".join(["Bob"]*100)): 2.11 => 0.92
("C"+"AB"*300).rfind("CA"): 0.57 => 1.03
("A" + ("Z"*128*1024)).replace("A", "BB", 1): 0.25 => 0.50

The rfind case is really strange: the code between Python 3.2 and 3.3 is 
exactly the same. Even in Python 3.2: rfind looks twice faster than find:

("AB"*300+"C").find("BC") (*1000) : 1.21
("C"+"AB"*300).rfind("CA") (*1000) : 0.57

stringbench is ASCII only, I expect worse performance with non-ASCII 
characters. Python 3.3 is now faster for pure ASCII (faster than other "kinds" 
of Unicode string).

Hopefuly, Python 3.3 is faster in some stringbench tests, sometimes 2 times 
faster ;-)

Victor
-------------- next part --------------
stringbench v2.0
3.3.0a0 (default:341c3002ffb2, Oct  6 2011, 01:52:36) 
[GCC 4.6.0 20110603 (Red Hat 4.6.0-10)]
2011-10-06 01:53:06.975247
bytes	unicode
(in ms)	(in ms)	%	comment
========== case conversion -- dense
0.40	1.59	25.2	("WHERE IN THE WORLD IS CARMEN SAN DEIGO?"*10).lower() (*1000)
0.42	1.55	27.3	("where in the world is carmen san deigo?"*10).upper() (*1000)
========== case conversion -- rare
0.53	1.49	35.8	("Where in the world is Carmen San Deigo?"*10).lower() (*1000)
0.44	1.55	28.5	("wHERE IN THE WORLD IS cARMEN sAN dEIGO?"*10).upper() (*1000)
========== concat 20 strings of words length 4 to 15
1.25	1.44	86.8	s1+s2+s3+s4+...+s20 (*1000)
========== concat two strings
0.06	0.07	92.5	"Andrew"+"Dalke" (*1000)
========== count AACT substrings in DNA example
1.27	1.32	96.5	dna.count("AACT") (*10)
========== count newlines
0.53	0.51	103.3	...text.with.2000.newlines.count("\n") (*10)
========== early match, single character
0.11	0.12	89.2	("A"*1000).find("A") (*1000)
0.31	0.03	887.7	"A" in "A"*1000 (*1000)
0.11	0.12	90.7	("A"*1000).index("A") (*1000)
0.13	0.14	94.4	("A"*1000).partition("A") (*1000)
0.12	0.13	90.3	("A"*1000).rfind("A") (*1000)
0.12	0.13	91.3	("A"*1000).rindex("A") (*1000)
0.12	0.13	94.7	("A"*1000).rpartition("A") (*1000)
0.28	0.27	102.0	("A"*1000).rsplit("A", 1) (*1000)
0.29	0.28	103.4	("A"*1000).split("A", 1) (*1000)
========== early match, two characters
0.11	0.13	90.5	("AB"*1000).find("AB") (*1000)
0.31	0.04	799.5	"AB" in "AB"*1000 (*1000)
0.11	0.13	89.2	("AB"*1000).index("AB") (*1000)
0.15	0.16	97.9	("AB"*1000).partition("AB") (*1000)
0.12	0.14	90.0	("AB"*1000).rfind("AB") (*1000)
0.12	0.13	92.8	("AB"*1000).rindex("AB") (*1000)
0.14	0.15	93.3	("AB"*1000).rpartition("AB") (*1000)
0.31	0.30	101.4	("AB"*1000).rsplit("AB", 1) (*1000)
0.32	0.32	101.0	("AB"*1000).split("AB", 1) (*1000)
========== endswith multiple characters
0.13	0.13	96.1	"Andrew".endswith("Andrew") (*1000)
========== endswith multiple characters - not!
0.13	0.12	108.4	"Andrew".endswith("Anders") (*1000)
========== endswith single character
0.13	0.13	94.9	"Andrew".endswith("w") (*1000)
========== formatting a string type with a dict
N/A	0.52	0.0	"The %(k1)s is %(k2)s the %(k3)s."%{"k1":"x","k2":"y","k3":"z",} (*1000)
========== join empty string, with 1 character sep
N/A	0.04	0.0	"A".join("") (*100)
========== join empty string, with 5 character sep
N/A	0.04	0.0	"ABCDE".join("") (*100)
========== join list of 100 words, with 1 character sep
1.10	2.11	52.3	"A".join(["Bob"]*100)) (*1000)
========== join list of 100 words, with 5 character sep
1.16	2.29	50.9	"ABCDE".join(["Bob"]*100)) (*1000)
========== join list of 26 characters, with 1 character sep
0.31	0.60	51.3	"A".join(list("ABC..Z")) (*1000)
========== join list of 26 characters, with 5 character sep
0.34	0.60	56.5	"ABCDE".join(list("ABC..Z")) (*1000)
========== join string with 26 characters, with 1 character sep
N/A	1.23	0.0	"A".join("ABC..Z") (*1000)
========== join string with 26 characters, with 5 character sep
N/A	1.21	0.0	"ABCDE".join("ABC..Z") (*1000)
========== late match, 100 characters
8.88	8.52	104.1	s="ABC"*33; ((s+"D")*500+s+"E").find(s+"E") (*100)
3.48	3.53	98.5	s="ABC"*33; ((s+"D")*500+"E"+s).find("E"+s) (*100)
5.33	5.28	100.9	s="ABC"*33; (s+"E") in ((s+"D")*300+s+"E") (*100)
8.88	8.60	103.2	s="ABC"*33; ((s+"D")*500+s+"E").index(s+"E") (*100)
9.24	9.24	100.0	s="ABC"*33; ((s+"D")*500+s+"E").partition(s+"E") (*100)
7.86	7.61	103.4	s="ABC"*33; ("E"+s+("D"+s)*500).rfind("E"+s) (*100)
1.76	1.98	88.9	s="ABC"*33; (s+"E"+("D"+s)*500).rfind(s+"E") (*100)
7.67	7.53	101.9	s="ABC"*33; ("E"+s+("D"+s)*500).rindex("E"+s) (*100)
7.88	7.74	101.9	s="ABC"*33; ("E"+s+("D"+s)*500).rpartition("E"+s) (*100)
8.22	8.22	100.0	s="ABC"*33; ("E"+s+("D"+s)*500).rsplit("E"+s, 1) (*100)
9.12	9.09	100.3	s="ABC"*33; ((s+"D")*500+s+"E").split(s+"E", 1) (*100)
========== late match, two characters
1.19	1.16	103.1	("AB"*300+"C").find("BC") (*1000)
1.18	1.18	99.2	("AB"*300+"CA").find("CA") (*1000)
1.38	1.10	125.7	"BC" in ("AB"*300+"C") (*1000)
1.21	1.16	104.2	("AB"*300+"C").index("BC") (*1000)
1.18	1.21	98.2	("AB"*300+"C").partition("BC") (*1000)
1.06	1.03	102.3	("C"+"AB"*300).rfind("CA") (*1000)
0.70	0.71	98.7	("BC"+"AB"*300).rfind("BC") (*1000)
1.04	1.03	100.9	("C"+"AB"*300).rindex("CA") (*1000)
1.03	1.05	97.6	("C"+"AB"*300).rpartition("CA") (*1000)
1.24	1.19	103.8	("C"+"AB"*300).rsplit("CA", 1) (*1000)
1.29	1.34	96.0	("AB"*300+"C").split("BC", 1) (*1000)
========== no match, single character
0.67	0.68	98.1	("A"*1000).find("B") (*1000)
0.86	0.59	145.4	"B" in "A"*1000 (*1000)
0.60	0.61	98.2	("A"*1000).partition("B") (*1000)
0.68	0.68	98.8	("A"*1000).rfind("B") (*1000)
0.61	0.62	99.5	("A"*1000).rpartition("B") (*1000)
0.71	0.71	100.2	("A"*1000).rsplit("B", 1) (*1000)
0.70	0.70	99.9	("A"*1000).split("B", 1) (*1000)
========== no match, two characters
3.64	3.50	103.9	("AB"*1000).find("BC") (*1000)
3.70	3.59	103.1	("AB"*1000).find("CA") (*1000)
3.86	3.56	108.4	"BC" in "AB"*1000 (*1000)
3.57	3.69	96.9	("AB"*1000).partition("BC") (*1000)
2.04	2.04	100.0	("AB"*1000).rfind("BC") (*1000)
3.17	3.14	100.7	("AB"*1000).rfind("CA") (*1000)
1.99	2.12	94.2	("AB"*1000).rpartition("BC") (*1000)
2.31	2.33	99.2	("AB"*1000).rsplit("BC", 1) (*1000)
3.75	3.74	100.1	("AB"*1000).split("BC", 1) (*1000)
========== quick replace multiple character match
0.06	0.49	11.3	("A" + ("Z"*128*1024)).replace("AZZ", "BBZZ", 1) (*10)
========== quick replace single character match
0.05	0.50	11.0	("A" + ("Z"*128*1024)).replace("A", "BB", 1) (*10)
========== repeat 1 character 10 times
0.06	0.07	86.0	"A"*10 (*1000)
========== repeat 1 character 1000 times
0.11	0.12	91.4	"A"*1000 (*1000)
========== repeat 5 characters 10 times
0.07	0.08	85.3	"ABCDE"*10 (*1000)
========== repeat 5 characters 1000 times
0.21	0.23	91.4	"ABCDE"*1000 (*1000)
========== replace and expand multiple characters, big string
0.83	1.80	46.0	"...text.with.2000.newlines...replace("\n", "\r\n") (*10)
========== replace multiple characters, dna
1.63	2.35	69.3	dna.replace("ATC", "ATT") (*10)
========== replace single character
0.13	0.17	73.9	"This is a test".replace(" ", "\t") (*1000)
========== replace single character, big string
0.23	1.37	16.5	"...text.with.2000.lines...replace("\n", " ") (*10)
========== replace/remove multiple characters
0.20	0.27	74.7	"When shall we three meet again?".replace("ee", "") (*1000)
========== split 1 whitespace
0.08	0.11	78.6	("Here are some words. "*2).partition(" ") (*1000)
0.07	0.08	84.3	("Here are some words. "*2).rpartition(" ") (*1000)
0.19	0.21	91.0	("Here are some words. "*2).rsplit(None, 1) (*1000)
0.18	0.20	93.2	("Here are some words. "*2).split(None, 1) (*1000)
========== split 2000 newlines
1.27	1.51	83.9	"...text...".rsplit("\n") (*10)
1.21	1.32	91.4	"...text...".split("\n") (*10)
1.44	1.71	84.1	"...text...".splitlines() (*10)
========== split newlines
0.22	0.27	82.9	"this\nis\na\ntest\n".rsplit("\n") (*1000)
0.22	0.24	91.4	"this\nis\na\ntest\n".split("\n") (*1000)
0.20	0.24	82.4	"this\nis\na\ntest\n".splitlines() (*1000)
========== split on multicharacter separator (dna)
1.09	1.10	98.8	dna.rsplit("ACTAT") (*10)
1.48	1.43	103.4	dna.split("ACTAT") (*10)
========== split on multicharacter separator (small)
0.40	0.46	88.4	"this--is--a--test--of--the--emergency--broadcast--system".rsplit("--") (*1000)
0.39	0.45	87.0	"this--is--a--test--of--the--emergency--broadcast--system".split("--") (*1000)
========== split whitespace (huge)
1.24	1.44	86.1	human_text.rsplit() (*10)
1.11	1.35	82.6	human_text.split() (*10)
========== split whitespace (small)
0.34	0.38	89.5	("Here are some words. "*2).rsplit() (*1000)
0.32	0.37	85.8	("Here are some words. "*2).split() (*1000)
========== startswith multiple characters
0.12	0.13	94.5	"Andrew".startswith("Andrew") (*1000)
========== startswith multiple characters - not!
0.12	0.11	109.7	"Andrew".startswith("Anders") (*1000)
========== startswith single character
0.12	0.13	95.4	"Andrew".startswith("A") (*1000)
========== strip terminal newline
0.06	0.16	39.1	s="Hello!\n"; s[:-1] if s[-1]=="\n" else s (*1000)
0.05	0.06	77.6	"\nHello!".rstrip() (*1000)
0.05	0.06	77.0	"Hello!\n".rstrip() (*1000)
0.05	0.07	74.4	"\nHello!\n".strip() (*1000)
0.05	0.06	75.8	"\nHello!".strip() (*1000)
0.05	0.06	75.3	"Hello!\n".strip() (*1000)
========== strip terminal spaces and tabs
0.05	0.07	70.1	"\t   \tHello".rstrip() (*1000)
0.05	0.07	76.5	"Hello\t   \t".rstrip() (*1000)
0.03	0.04	78.7	"Hello\t   \t".strip() (*1000)
========== tab split
0.36	0.48	75.4	GFF3_example.rsplit("\t", 8) (*1000)
0.34	0.46	73.2	GFF3_example.rsplit("\t") (*1000)
0.30	0.42	70.5	GFF3_example.split("\t", 8) (*1000)
0.32	0.43	73.4	GFF3_example.split("\t") (*1000)
152.32	166.34	91.6	TOTAL
-------------- next part --------------
stringbench v2.0
3.2.2+ (3.2:125887a41a6f, Oct  5 2011, 22:29:03) 
[GCC 4.6.0 20110603 (Red Hat 4.6.0-10)]
2011-10-05 22:48:28.819039
bytes	unicode
(in ms)	(in ms)	%	comment
========== case conversion -- dense
0.44	1.46	30.0	("WHERE IN THE WORLD IS CARMEN SAN DEIGO?"*10).lower() (*1000)
0.46	1.38	33.3	("where in the world is carmen san deigo?"*10).upper() (*1000)
========== case conversion -- rare
0.59	1.40	42.1	("Where in the world is Carmen San Deigo?"*10).lower() (*1000)
0.48	1.40	34.1	("wHERE IN THE WORLD IS cARMEN sAN dEIGO?"*10).upper() (*1000)
========== concat 20 strings of words length 4 to 15
1.26	1.50	83.7	s1+s2+s3+s4+...+s20 (*1000)
========== concat two strings
0.06	0.05	129.1	"Andrew"+"Dalke" (*1000)
========== count AACT substrings in DNA example
1.26	1.27	99.6	dna.count("AACT") (*10)
========== count newlines
0.53	0.53	99.1	...text.with.2000.newlines.count("\n") (*10)
========== early match, single character
0.12	0.12	101.5	("A"*1000).find("A") (*1000)
0.32	0.03	1139.8	"A" in "A"*1000 (*1000)
0.12	0.12	104.4	("A"*1000).index("A") (*1000)
0.13	0.20	66.6	("A"*1000).partition("A") (*1000)
0.13	0.12	103.5	("A"*1000).rfind("A") (*1000)
0.13	0.12	102.9	("A"*1000).rindex("A") (*1000)
0.13	0.20	63.2	("A"*1000).rpartition("A") (*1000)
0.29	0.34	84.8	("A"*1000).rsplit("A", 1) (*1000)
0.29	0.35	82.4	("A"*1000).split("A", 1) (*1000)
========== early match, two characters
0.12	0.12	103.2	("AB"*1000).find("AB") (*1000)
0.32	0.03	1050.5	"AB" in "AB"*1000 (*1000)
0.12	0.12	103.4	("AB"*1000).index("AB") (*1000)
0.15	0.26	60.0	("AB"*1000).partition("AB") (*1000)
0.13	0.12	104.1	("AB"*1000).rfind("AB") (*1000)
0.13	0.13	101.9	("AB"*1000).rindex("AB") (*1000)
0.15	0.25	60.7	("AB"*1000).rpartition("AB") (*1000)
0.31	0.42	73.4	("AB"*1000).rsplit("AB", 1) (*1000)
0.32	0.42	76.7	("AB"*1000).split("AB", 1) (*1000)
========== endswith multiple characters
0.13	0.15	89.1	"Andrew".endswith("Andrew") (*1000)
========== endswith multiple characters - not!
0.13	0.11	111.1	"Andrew".endswith("Anders") (*1000)
========== endswith single character
0.12	0.13	95.1	"Andrew".endswith("w") (*1000)
========== formatting a string type with a dict
N/A	0.43	0.0	"The %(k1)s is %(k2)s the %(k3)s."%{"k1":"x","k2":"y","k3":"z",} (*1000)
========== join empty string, with 1 character sep
N/A	0.04	0.0	"A".join("") (*100)
========== join empty string, with 5 character sep
N/A	0.04	0.0	"ABCDE".join("") (*100)
========== join list of 100 words, with 1 character sep
1.13	0.92	122.6	"A".join(["Bob"]*100)) (*1000)
========== join list of 100 words, with 5 character sep
1.17	0.96	122.0	"ABCDE".join(["Bob"]*100)) (*1000)
========== join list of 26 characters, with 1 character sep
0.32	0.27	118.2	"A".join(list("ABC..Z")) (*1000)
========== join list of 26 characters, with 5 character sep
0.32	0.32	100.9	"ABCDE".join(list("ABC..Z")) (*1000)
========== join string with 26 characters, with 1 character sep
N/A	0.93	0.0	"A".join("ABC..Z") (*1000)
========== join string with 26 characters, with 5 character sep
N/A	1.00	0.0	"ABCDE".join("ABC..Z") (*1000)
========== late match, 100 characters
8.73	8.80	99.2	s="ABC"*33; ((s+"D")*500+s+"E").find(s+"E") (*100)
3.44	3.49	98.5	s="ABC"*33; ((s+"D")*500+"E"+s).find("E"+s) (*100)
5.41	5.37	100.8	s="ABC"*33; (s+"E") in ((s+"D")*300+s+"E") (*100)
9.04	9.01	100.3	s="ABC"*33; ((s+"D")*500+s+"E").index(s+"E") (*100)
8.91	10.90	81.7	s="ABC"*33; ((s+"D")*500+s+"E").partition(s+"E") (*100)
7.49	3.48	215.0	s="ABC"*33; ("E"+s+("D"+s)*500).rfind("E"+s) (*100)
1.81	1.95	92.7	s="ABC"*33; (s+"E"+("D"+s)*500).rfind(s+"E") (*100)
7.71	3.90	197.4	s="ABC"*33; ("E"+s+("D"+s)*500).rindex("E"+s) (*100)
7.77	4.23	184.0	s="ABC"*33; ("E"+s+("D"+s)*500).rpartition("E"+s) (*100)
8.18	4.25	192.4	s="ABC"*33; ("E"+s+("D"+s)*500).rsplit("E"+s, 1) (*100)
9.22	9.93	92.9	s="ABC"*33; ((s+"D")*500+s+"E").split(s+"E", 1) (*100)
========== late match, two characters
1.23	1.21	101.5	("AB"*300+"C").find("BC") (*1000)
1.19	1.16	101.9	("AB"*300+"CA").find("CA") (*1000)
1.38	1.08	128.6	"BC" in ("AB"*300+"C") (*1000)
1.19	1.18	100.6	("AB"*300+"C").index("BC") (*1000)
1.19	1.38	86.1	("AB"*300+"C").partition("BC") (*1000)
1.05	0.57	184.5	("C"+"AB"*300).rfind("CA") (*1000)
0.70	0.70	99.7	("BC"+"AB"*300).rfind("BC") (*1000)
1.04	0.58	181.4	("C"+"AB"*300).rindex("CA") (*1000)
1.03	0.61	168.3	("C"+"AB"*300).rpartition("CA") (*1000)
1.24	0.77	161.1	("C"+"AB"*300).rsplit("CA", 1) (*1000)
1.32	1.39	95.1	("AB"*300+"C").split("BC", 1) (*1000)
========== no match, single character
0.68	0.68	100.2	("A"*1000).find("B") (*1000)
0.89	0.59	151.2	"B" in "A"*1000 (*1000)
0.60	0.60	99.9	("A"*1000).partition("B") (*1000)
0.69	0.68	100.8	("A"*1000).rfind("B") (*1000)
0.61	0.60	100.9	("A"*1000).rpartition("B") (*1000)
0.71	0.72	99.2	("A"*1000).rsplit("B", 1) (*1000)
0.71	0.70	101.7	("A"*1000).split("B", 1) (*1000)
========== no match, two characters
3.69	3.65	101.3	("AB"*1000).find("BC") (*1000)
3.64	3.63	100.3	("AB"*1000).find("CA") (*1000)
3.87	3.54	109.2	"BC" in "AB"*1000 (*1000)
3.58	4.12	87.0	("AB"*1000).partition("BC") (*1000)
2.05	2.02	101.6	("AB"*1000).rfind("BC") (*1000)
3.16	1.62	195.0	("AB"*1000).rfind("CA") (*1000)
2.02	2.03	99.6	("AB"*1000).rpartition("BC") (*1000)
2.36	2.15	109.8	("AB"*1000).rsplit("BC", 1) (*1000)
3.66	3.67	99.9	("AB"*1000).split("BC", 1) (*1000)
========== quick replace multiple character match
0.06	0.28	19.9	("A" + ("Z"*128*1024)).replace("AZZ", "BBZZ", 1) (*10)
========== quick replace single character match
0.05	0.25	21.2	("A" + ("Z"*128*1024)).replace("A", "BB", 1) (*10)
========== repeat 1 character 10 times
0.06	0.06	90.5	"A"*10 (*1000)
========== repeat 1 character 1000 times
0.10	0.19	54.6	"A"*1000 (*1000)
========== repeat 5 characters 10 times
0.07	0.08	90.7	"ABCDE"*10 (*1000)
========== repeat 5 characters 1000 times
0.20	0.51	39.9	"ABCDE"*1000 (*1000)
========== replace and expand multiple characters, big string
0.84	1.69	49.7	"...text.with.2000.newlines...replace("\n", "\r\n") (*10)
========== replace multiple characters, dna
1.66	1.90	87.3	dna.replace("ATC", "ATT") (*10)
========== replace single character
0.13	0.14	95.0	"This is a test".replace(" ", "\t") (*1000)
========== replace single character, big string
0.22	0.65	34.6	"...text.with.2000.lines...replace("\n", " ") (*10)
========== replace/remove multiple characters
0.20	0.23	90.5	"When shall we three meet again?".replace("ee", "") (*1000)
========== split 1 whitespace
0.08	0.08	91.6	("Here are some words. "*2).partition(" ") (*1000)
0.06	0.08	83.8	("Here are some words. "*2).rpartition(" ") (*1000)
0.21	0.24	87.0	("Here are some words. "*2).rsplit(None, 1) (*1000)
0.20	0.21	95.1	("Here are some words. "*2).split(None, 1) (*1000)
========== split 2000 newlines
1.29	1.90	67.9	"...text...".rsplit("\n") (*10)
1.22	1.75	70.1	"...text...".split("\n") (*10)
1.45	1.99	72.8	"...text...".splitlines() (*10)
========== split newlines
0.24	0.20	117.2	"this\nis\na\ntest\n".rsplit("\n") (*1000)
0.23	0.20	115.6	"this\nis\na\ntest\n".split("\n") (*1000)
0.21	0.20	105.6	"this\nis\na\ntest\n".splitlines() (*1000)
========== split on multicharacter separator (dna)
1.09	0.85	128.6	dna.rsplit("ACTAT") (*10)
1.47	1.60	91.5	dna.split("ACTAT") (*10)
========== split on multicharacter separator (small)
0.42	0.45	93.5	"this--is--a--test--of--the--emergency--broadcast--system".rsplit("--") (*1000)
0.42	0.38	110.1	"this--is--a--test--of--the--emergency--broadcast--system".split("--") (*1000)
========== split whitespace (huge)
1.21	1.61	75.5	human_text.rsplit() (*10)
1.13	1.67	67.3	human_text.split() (*10)
========== split whitespace (small)
0.35	0.34	100.9	("Here are some words. "*2).rsplit() (*1000)
0.33	0.31	106.1	("Here are some words. "*2).split() (*1000)
========== startswith multiple characters
0.13	0.14	91.7	"Andrew".startswith("Andrew") (*1000)
========== startswith multiple characters - not!
0.13	0.11	114.9	"Andrew".startswith("Anders") (*1000)
========== startswith single character
0.13	0.13	97.9	"Andrew".startswith("A") (*1000)
========== strip terminal newline
0.06	0.13	47.5	s="Hello!\n"; s[:-1] if s[-1]=="\n" else s (*1000)
0.04	0.04	107.5	"\nHello!".rstrip() (*1000)
0.05	0.04	105.7	"Hello!\n".rstrip() (*1000)
0.05	0.05	100.0	"\nHello!\n".strip() (*1000)
0.04	0.04	100.8	"\nHello!".strip() (*1000)
0.05	0.04	105.8	"Hello!\n".strip() (*1000)
========== strip terminal spaces and tabs
0.05	0.04	102.1	"\t   \tHello".rstrip() (*1000)
0.05	0.05	104.7	"Hello\t   \t".rstrip() (*1000)
0.03	0.03	90.3	"Hello\t   \t".strip() (*1000)
========== tab split
0.35	0.37	92.7	GFF3_example.rsplit("\t", 8) (*1000)
0.33	0.36	92.9	GFF3_example.rsplit("\t") (*1000)
0.30	0.31	96.5	GFF3_example.split("\t", 8) (*1000)
0.31	0.33	94.3	GFF3_example.split("\t") (*1000)
152.31	146.96	103.6	TOTAL


More information about the Python-Dev mailing list