Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does periodically pressing the enter key substantially speed up my code?

I inadvertently ran across a phenomenon that has me a bit perplexed. I was using IDLE for some quick testing, and I had some very simple code like this (which I have simplified for the purpose of illustration):

from time import clock  # I am presently using windows

def test_speedup():
    c = clock()
    for i in range(1000):
        print i,
    print '=>', clock() - c

Now I ran this code like so (several times, with the same basic results):

# without pressing enter
>>> test_speedup()
0 1 2 3 4 . . . 997 998 999 => 12.8300956124  # the time to run code in seconds

# pressing enter ONLY 3 TIMES while the code ran
>>> test_speedup()
0 1 2 3 4 . . . 997 998 999 => 4.8656890089

# Pressing enter several times while the code ran
>>> test_speedup()
0 1 2 3 4 . . . 997 998 999 => 1.91522580283

My first hunch was that perhaps the code ran faster because the output system perhaps did not have to collate as many strings when I pressed enter (beginning anew each time I pressed enter). In fact, the output system always seemed to receive a boost in speed immediately after I pressed enter.

I have also reviewed the documentation here, but I am still a little puzzled why three newline characters would speed things up so substantially.

This question is admittedly somewhat trivial, unless one would like to know how to speed up the output system in IDLE without aborting the script. Still, I would like to understand what is happening with the output system here.

(I am using Python 2.7.x.)

like image 594
user3079064 Avatar asked Feb 14 '14 00:02

user3079064


1 Answers

Under the covers, IDLE is simulating a terminal on top of a Tk widget, which I'm pretty sure is ultimately derived from Text.

The presence of long lines slows down that widget a little bit. And appending to long lines takes longer than appending to short ones. If you really want to understand why this happens, you need to look at the Tcl code underlying the Tk Text widget, which Tkinter.Text is just a thin wrapper around.

Meanwhile, the Tkinter loop that IDLE runs does some funky things to allow it to accept input without blocking the loop. When it thinks there's nothing else going on, it may sometimes block for a short time until it sees input or a Tk event, and all of those short blocks may add up; pressing Enter may just cancel a few of them.

I'm not actually sure which of these two is more relevant here. You'd have to test it with a program that just spams long lines vs. one that inserts newlines every, say, 10 numbers, and see how much of the performance improvement you get that way.

From a quick test on my Mac, the original program visibly slows down gradually, and also has two quantum jumps in sluggishness around 500 and 920. So, it makes sense that hitting enter every 333 or so would speed things up a lot—you likely avoid both of those quantum slowdowns. If I change it to just remove the comma, the problem goes away.

Printing a newline for every number could of course cause a different slowdown, because that makes the terminal long enough to need to scroll, increases the scrollback buffer, etc. I didn't see that cost in IDLE, but run the same thing on the Windows command line, and you'll see problems with too many newlines just as bad as the problems with too few in IDLE. The best tradeoff should probably come from "square"-ish data, or data that's as close to 80 columns as possible without going over.

like image 91
abarnert Avatar answered Sep 28 '22 01:09

abarnert