I am currently trying to cleanup/improve on some code I finally got working.
Which of the two is faster between a while loop and the same command written over and over a set number of times.
EG.
count = 0
while count < 10:
print('hello')
count = 1
OR
print('hello')
print('hello')
print('hello')
print('hello')
print('hello')
print('hello')
print('hello')
print('hello')
print('hello')
print('hello')
The while loop is cleaner but is it faster? I am still quite new to this so my understanding is that in terms of the above procedural code, the while loop will run 32 statements in total compared to the print only statements which would run 10 times only:
- count is initially set to zero
- while evaluates count to be less than 10 (0)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (1)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (2)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (3)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (4)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (5)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (6)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (7)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (8)
- hello is printed
- count is incremented by one
- while evaluates count to be less than 10 (9)
- hello is printed
- count is incremented by one
- while evaluates count to no longer be less than 10 (10) While loop breaks out and processing ends
Based on the above, I would assume that the advantage of the while loop is neatness in code and speed of writing that code (not necessarily the speed in execution, albeit with computers been so powerful, one wouldn't notice.)
Am I correct in the above assumption?
EDIT: That was quick, I see some answers confirming my initial thoughts about optimization. Thanks.
The above code example is not related to my project, its just to show understanding.
CodePudding user response:
If in doubt: measure.
What is better?
- fewer bytecode? ==>
import dis
and compare bytecode - faster execution ==>
import timeit
and compare runtimes - readability ==> depends on your weakest cowororkers ability to grok¹ your code (run a file with
import this
² as code ;o)
like so:
import dis
import timeit
def a():
count = 0
p = print # local caching of global lookup - way faster
while count < 10:
p('hello', flush=True)
count = 1
def b():
p = print # local caching of global lookup - way faster
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
def c():
print( *("hello" for _ in range(10)), sep="\n", flush=True)
aa = timeit.timeit(a, number=100)
bb = timeit.timeit(b, number=100)
cc = timeit.timeit(c, number=100)
print(aa, bb, cc, sep="\n")
dis.dis(a)
print("-"*80)
dis.dis(b)
print("-"*80)
dis.dis(c)
to get
0.059448799999699986 # while is faster - who would have thought
0.06415420000030281 # multiple prints
0.06454990000020189 # one print but list comp
# while loop - seems to be shortest
5 0 LOAD_CONST 1 (0)
2 STORE_FAST 0 (count)
6 4 LOAD_GLOBAL 0 (print)
6 STORE_FAST 1 (p)
7 8 LOAD_FAST 0 (count)
10 LOAD_CONST 2 (10)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 24 (to 48)
8 >> 16 LOAD_FAST 1 (p)
18 LOAD_CONST 3 ('hello')
20 LOAD_CONST 4 (True)
22 LOAD_CONST 5 (('flush',))
24 CALL_FUNCTION_KW 2
26 POP_TOP
9 28 LOAD_FAST 0 (count)
30 LOAD_CONST 6 (1)
32 INPLACE_ADD
34 STORE_FAST 0 (count)
7 36 LOAD_FAST 0 (count)
38 LOAD_CONST 2 (10)
40 COMPARE_OP 0 (<)
42 POP_JUMP_IF_TRUE 8 (to 16)
44 LOAD_CONST 0 (None)
46 RETURN_VALUE
>> 48 LOAD_CONST 0 (None)
50 RETURN_VALUE
--------------------------------------------------------------------------------
# multiple prints
11 0 LOAD_GLOBAL 0 (print)
2 STORE_FAST 0 (p)
12 4 LOAD_FAST 0 (p)
6 LOAD_CONST 1 ('hello')
8 LOAD_CONST 2 (True)
10 LOAD_CONST 3 (('flush',))
12 CALL_FUNCTION_KW 2
14 POP_TOP
13 16 LOAD_FAST 0 (p)
18 LOAD_CONST 1 ('hello')
20 LOAD_CONST 2 (True)
22 LOAD_CONST 3 (('flush',))
24 CALL_FUNCTION_KW 2
26 POP_TOP
14 28 LOAD_FAST 0 (p)
30 LOAD_CONST 1 ('hello')
32 LOAD_CONST 2 (True)
34 LOAD_CONST 3 (('flush',))
36 CALL_FUNCTION_KW 2
38 POP_TOP
15 40 LOAD_FAST 0 (p)
42 LOAD_CONST 1 ('hello')
44 LOAD_CONST 2 (True)
46 LOAD_CONST 3 (('flush',))
48 CALL_FUNCTION_KW 2
50 POP_TOP
16 52 LOAD_FAST 0 (p)
54 LOAD_CONST 1 ('hello')
56 LOAD_CONST 2 (True)
58 LOAD_CONST 3 (('flush',))
60 CALL_FUNCTION_KW 2
62 POP_TOP
17 64 LOAD_FAST 0 (p)
66 LOAD_CONST 1 ('hello')
68 LOAD_CONST 2 (True)
70 LOAD_CONST 3 (('flush',))
72 CALL_FUNCTION_KW 2
74 POP_TOP
18 76 LOAD_FAST 0 (p)
78 LOAD_CONST 1 ('hello')
80 LOAD_CONST 2 (True)
82 LOAD_CONST 3 (('flush',))
84 CALL_FUNCTION_KW 2
86 POP_TOP
19 88 LOAD_FAST 0 (p)
90 LOAD_CONST 1 ('hello')
92 LOAD_CONST 2 (True)
94 LOAD_CONST 3 (('flush',))
96 CALL_FUNCTION_KW 2
98 POP_TOP
20 100 LOAD_FAST 0 (p)
102 LOAD_CONST 1 ('hello')
104 LOAD_CONST 2 (True)
106 LOAD_CONST 3 (('flush',))
108 CALL_FUNCTION_KW 2
110 POP_TOP
21 112 LOAD_FAST 0 (p)
114 LOAD_CONST 1 ('hello')
116 LOAD_CONST 2 (True)
118 LOAD_CONST 3 (('flush',))
120 CALL_FUNCTION_KW 2
122 POP_TOP
124 LOAD_CONST 0 (None)
126 RETURN_VALUE
--------------------------------------------------------------------------------
# fancy generator comprehension
24 0 LOAD_GLOBAL 0 (print)
2 LOAD_CONST 1 (<code object <genexpr> at 0x000002320A8468C0, file "c:\Users\partner\Documents\Coding\python\t.py", line 24>)
4 LOAD_CONST 2 ('c.<locals>.<genexpr>')
6 MAKE_FUNCTION 0
8 LOAD_GLOBAL 1 (range)
10 LOAD_CONST 3 (10)
12 CALL_FUNCTION 1
14 GET_ITER
16 CALL_FUNCTION 1
18 LOAD_CONST 4 ('\n')
20 LOAD_CONST 5 (True)
22 LOAD_CONST 6 (('sep', 'flush'))
24 BUILD_CONST_KEY_MAP 2
26 CALL_FUNCTION_EX 1
28 POP_TOP
30 LOAD_CONST 0 (None)
32 RETURN_VALUE
Disassembly of <code object <genexpr> at 0x000002320A8468C0, file "c:\Users\partner\Documents\Coding\python\t.py", line 24>:
0 GEN_START 0
24 2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 5 (to 16)
6 STORE_FAST 1 (_)
8 LOAD_CONST 0 ('hello')
10 YIELD_VALUE
12 POP_TOP
14 JUMP_ABSOLUTE 2 (to 4)
>> 16 LOAD_CONST 1 (None)
18 RETURN_VALUE
¹) Coined by Robert A. Heinlein in his science fiction novel Stranger in a Strange Land source.