Search code examples
pythontimeshort-circuiting

Timing the shortcircuit in Python gives unexpected results


import time as dt 

success = True
can_test = True 


time = 0

for i in range(10000000):
  start = dt.time()
  if success and can_test:
    stop = dt.time()
    time+= stop-start


print(f'"and" operation took: {time} seconds')


time = 0

for i in range(10000000):
  start = dt.time()
  if success or can_test:
    stop = dt.time()
    time += stop-start


print(f'"or" operation took: {time} seconds')

When I run the above python program, I expect the and operation to be slower than the or operation (because I learned short-circuiting will reduce the time of execution). However, not only does the result turn out exact opposite but is also fluctuating. I can understand the fluctuation! (because of background processes). But why are the results turn out opposite! what is happening?

Here is a sample result.


"and" operation took: 5.200342893600464 seconds
"or" operation took: 5.3243467807769775 seconds


Solution

  • That was an interesting question, so I decided to deeply investigate your main concern.

    # required modules line_profiler, matplotlib, seaborn abd scipy
    import time as dt 
    from line_profiler import LineProfiler
    import matplotlib.pyplot as plt
    import seaborn as sns
    from scipy import stats
    
    success = True
    can_test = True 
    def and_op():
        for x in range(2000):
            s = success and can_test
    def or_op():
        for x in range(2000):
            s = success or can_test
    or_op_list = []
    for x in range(0,1000):
        lp = LineProfiler()
        lp_wrapper = lp(or_op)
        lp_wrapper()
        lstats = lp.get_stats()
        total_time = 0
        for v in lstats.timings.values():
            for op in v:
                total_time += op[-1]
                final = op[-1]
            operator = final/total_time
        or_op_list.append(operator)
    
    and_op_list = []
    for x in range(0,1000):
        lp = LineProfiler()
        lp_wrapper = lp(and_op)
        lp_wrapper()
        lstats = lp.get_stats()
        total_time = 0
        for v in lstats.timings.values():
            for op in v:
                total_time += op[-1]
                final = op[-1]
            operator = final/total_time
        and_op_list.append(operator)
    sns.kdeplot(and_op_list, label = 'AND')
    sns.kdeplot(or_op_list, label = 'OR')
    plt.show()
    print(stats.ttest_ind(and_op_list,or_op_list, equal_var = False))
    

    enter image description here

    pvalue=1.8293386245013954e-103

    Indeed the "or" is statistically significant and different as compared to the "and" operation