2

I have a child function that will iterate over 1000000 times. Now when I call that child function on two different functions. It's showing different time is taken for every execution. Why this is happening?

import timeit

def child():
    for i in range(1_000_000):
        yield i

def slow():
    yield from child()

def fast():
    yield from child()

baseline = timeit.timeit(
    stmt='for _ in slow(): pass',
    globals=globals(),
    number=50
)
comparision = timeit.timeit(
    stmt='for _ in fast(): pass',
    globals=globals(),
    number=50
)
print(f'Manual nesting {baseline:.2f}s')
print(f'Composed nesting {comparision:.2f}s')

Output

# First execution
Manual nesting 9.94s
Composed nesting 9.35s

# Second execution
Manual nesting 9.20s
Composed nesting 9.77s

As you have already seen the above output. It's showing different time intervals. Why does it happen for the same process?

mhhabib
  • 2,975
  • 1
  • 15
  • 29
  • Does this answer your question? [why same python code has different clock time?](https://stackoverflow.com/questions/52018018/why-same-python-code-has-different-clock-time) – Shiva Jan 11 '21 at 04:21
  • I don't understand the question. Are you expecting it to always take the exact same amount of time, up to an attosecond? Perhaps you might want to read up on binomial or normal distributions. – Mateen Ulhaq Jan 11 '21 at 04:23
  • @MateenUlhaq Yes, I am expecting the almost same amount of time should be taken. – mhhabib Jan 11 '21 at 04:39
  • @Shiva No, that wasn't the answer – mhhabib Jan 11 '21 at 04:40
  • @toRex Any Python function will take different amount of time on different runs, close to each other but still a bit different. One obvious reason is that you your operating system (Windows, Linux...) you have many processes running. They are all switching threads all the time at different points of time. Hence your Python execution thread is not continuous, it may stop in the middle and continue a bit later when operating system schedules it again. – Arty Feb 09 '21 at 07:23
  • @toRex Another reason is that CPU cores always slow down (if a bit overheated) or boost (on turbo frequency). Another reason is that on each function run there are different conditions of whole Python environment - for example memory manager will have different size or length of list of free memory chunks, hence every time it will take different amount of CPU time to allocate memory for each Python object. And there are many more reasons. All these reasons sum up to final small difference in time. – Arty Feb 09 '21 at 07:23
  • @Arty, exactly. Thread scheduling is the reason they have different through-put times at different executions. – nipun Feb 09 '21 at 07:41
  • I don’t see any issue here. Your timings are entirely expected and variation like this is normal. – Martijn Pieters Feb 13 '21 at 09:38
  • Your question title is also confusing. Your example isn’t composing anything. Did you mean “comparing” instead? The `slow()` and `fast()` functions are *exactly the same* and so are the “manual” and “composed” timers. It is unclear what your are even comparing here, and on a second run your “fast” timings are slower than the “slow” timings (as expected as they are the same function). – Martijn Pieters Feb 13 '21 at 09:39

1 Answers1

4

Any Python function will take different amount of time on each run, close to each other but a bit different. There are many reasons:

  1. Your operating system (Windows, Linux, etc...) has many processes and threads. Each process and thread is scheduled to be run only for a small amount of continuous time, usually several milliseconds, then process/thread switches to another one. It means that your execution process may suspend in the middle, then continue after some time when operating system reschedules it. So running program is not continuous process.
  2. Evey modern CPU executes each instruction also at different amount of time each time. There are different prediction algorithms and caching algorithms and out of order execution and look ahead buffers, etc. All of these result in slightly different time of execution of each small instruction.
  3. CPU cores may change their running speed, frequency. Sometimes they slow down (when overheated) or boost for short time (on turbo frequency). This means on each run CPU core speed may change at random points of time.
  4. Also when each run of function is done Python has a bit different execution environment. For example memory manager may have a different list of free memory chunks (another length, other sizes of chunks, etc), so allocating each Python object will take different amount of time for each single Python instruction that does memory allocation, and Python does a lot.
  5. Also Python may run extra service threads in background, they will also occupy different part of execution time of your main process. Because of GIL, which blocks all other threads while any single Python thread is running.
  6. Also if your function is not deterministic on inputs (and your function is deterministic) then it may run different amount of time on each run because it basically executes different sequence of opcodes.

All these reasons and many more make whole Python execution system unpredictable time-wise, meaning that each run of function will have slightly (and sometimes even huge) difference in time.

Even not only for Python but for any program running on computer most of these reasons are applicable and any program will vary in speed on each execution. I suppose there might exist some special programming languages that may synchronize execution of each instruction/opcode to some high-resolution clock, for example on Mars landing spacecraft execution of each function may be needed to be exact up to nanoseconds. Then for programs written in such languages timings will be almost precise. But not for Python, it doesn't do any time-synchronization when running opcodes.

Arty
  • 14,883
  • 6
  • 36
  • 69