How do I avoid the Tkinter 30 msec polling loop.

Mike Clarkson support at internetdiscovery.com
Sat Mar 17 16:20:19 EST 2001


On 16 Mar 2001 05:10:25 GMT, pj at sgi.com (Paul Jackson) wrote:
>
> [Sorry if this is a repeat - I don't see my post from yesterday. -pj]
>
>I have a little 'biff' (BSD-speak for email watchdog) like
>program, written in Python, using Tkinter, that shows one of
>two text messages in a little window, depending on whether my
>email box has new mail in it.  The app polls the mailbox every
>minute, with an os.stat() call.
>
>Unfortunately, the app consumes cpu almost continuously,
>even when I wish it would sleep for the minute.
>
>The same busy loop can be see even on the smallest "Hello,
>world" example, such as:
>
>    import Tkinter
>    root = Tkinter.Tk()
>    label = Tkinter.Label(root, text = "Hello, world.")
>    label.pack()
>    root.mainloop()
>
>A system call trace of the above, on Irix 6.5.11, using
>
>    Python 2.1a1 (#23, Feb  2 2001, 17:25:50) [C] on irix6,
>
>shows the following 2 select() system calls, every 30 msec,
>non-stop:
>
> hello.py( 3693): select(4, [3], [<empty>], [<empty>], {sec=0, usec=0})
> hello.py( 3693): select(0, 0, 0, 0, {sec=0, usec=20000})
>
>This is on a system with a 10 msec TICK, and a timeout on
>the select of 20 msec, which ends up taking 30 msec each
>loop (timeouts are rounded up to the next TICK).
>
>===
>
>Anyhow, is there anyway to stop or radically slow this loop?

The short answer is no - you cannot stop or radically slow this loop.

It comes from  the way _tkinter.c is handling threads, tcl events
and Python signals. I spoke to Guido about it at Python9, and am
hoping we can do a non-looping solution using Tcl_CreateEventSource.

For the long answer, look at the attached email I sent to someone
who kindly offered to help take a look at this problem.

>                          I won't rest till it's the best ...
>                          Manager, Linux System Software
>                          Paul Jackson <pj at sgi.com> 1.650.933.1373

If you can't rest until it's the best, and if you know Tcl and Python,
send me email, and maybe you can help solve this misfeature.

Mike.

----------------------------------------------------------------------------------------
At 03:26 PM 1/29/01 +0100, you wrote:
Subject: Fundamental Tkinter inefficiency?

I'm looking at the implementation of Tk_MainLoop in _tkinter.c:

	quitMainLoop = 0;
	while (Tk_GetNumMainWindows() > threshold &&
	       !quitMainLoop &&
	       !errorInCmd)
	{
		int result;

#ifdef WITH_THREAD
		Py_BEGIN_ALLOW_THREADS
		PyThread_acquire_lock(tcl_lock, 1);
		tcl_tstate = tstate;
		result = Tcl_DoOneEvent(TCL_DONT_WAIT);
		tcl_tstate = NULL;
		PyThread_release_lock(tcl_lock);
		if (result == 0)
			Sleep(20);
		Py_END_ALLOW_THREADS
#else
		result = Tcl_DoOneEvent(0);
#endif

		if (PyErr_CheckSignals() != 0)
			return NULL;
		if (result < 0)
			break;
	}


and was wondering if it would be better to use a Tcl Event procedure
with a MaxBlock time to check the Python signals, instead of calling
Sleep.  Then it wouldn't be calling a hard sleep.  This means Python
burns a fair amount of CPU idling. You can see a significant
difference between Tk applications and the identical TkInter
application for CPU usage, I suspect because of this tight Sleep loop.
This even if you don't "use" threads - it's if you compile with
threads enabled.   

The idea would be to establish a Tcl Event procedure that would check
for Python signals every (say) 100 msec., and handle Tcl events all of
the rest of the time.

Does anyone know how to do this in Tcl - it shouldn't be more than a
few lines I suspect. Look at Tcl_CreateEventSource and
Tcl_SetMaxBlockTime in tcl/generic/tclNotify.c

Many thanks,

Mike.




More information about the Python-list mailing list