WARNING: The threading support is still somewhat experimental, and it has only seen reasonable testing under Linux. Threaded code is particularly tricky to debug, and it tends to show extremely platform-dependent behavior. Since I only have access to Linux machines, I will have to rely on user's experiences and assistance for this area of IPython to improve under other platforms.
IPython, via the -gthread , -qthread and -wthread options (described in Sec. 5.1), can run in multithreaded mode to support pyGTK, Qt and WXPython applications respectively. These GUI toolkits need to control the python main loop of execution, so under a normal Python interpreter, starting a pyGTK, Qt or WXPython application will immediately freeze the shell.
IPython, with one of these options (you can only use one at a time), separates the graphical loop and IPython's code execution run into different threads. This allows you to test interactively (with %run, for example) your GUI code without blocking.
A nice mini-tutorial on using IPython along with the Qt Designer application is available at the SciPy wiki: http://www.scipy.org/wikis/topical_software/QtWithIPythonAndDesigner.
As indicated in Sec. 5.1, a special -tk option is provided to try and allow Tk graphical applications to coexist interactively with WX, Qt or GTK ones. Whether this works at all, however, is very platform and configuration dependent. Please experiment with simple test cases before committing to using this combination of Tk and GTK/Qt/WX threading in a production environment.
When any of the thread systems (GTK, Qt or WX) are active, either directly or via -pylab with a threaded backend, it is impossible to interrupt long-running Python code via Ctrl-C. IPython can not pass the KeyboardInterrupt exception (or the underlying SIGINT) across threads, so any long-running process started from IPython will run to completion, or will have to be killed via an external (OS-based) mechanism.
To the best of my knowledge, this limitation is imposed by the Python interpreter itself, and it comes from the difficulty of writing portable signal/threaded code. If any user is an expert on this topic and can suggest a better solution, I would love to hear about it. In the IPython sources, look at the Shell.py module, and in particular at the runcode() method.
Be mindful that the Python interpreter switches between threads every bytecodes,
where the default value as of Python 2.3 is
This value can be read by
using the sys.getcheckinterval() function, and it can be reset via sys.setcheckinterval(N).
This switching of threads can cause subtly confusing effects if one of your threads
is doing file I/O. In text mode, most systems only flush file buffers when they
encounter a `\n'. An instruction as simple as
print >> filehandle, ``hello world''
actually consists of several bytecodes, so it is possible that the newline does
not reach your file before the next thread switch. Similarly, if you are writing
to a file in binary mode, the file won't be flushed until the buffer fills, and
your other thread may see apparently truncated files.
For this reason, if you are using IPython's thread support and have (for example)
a GUI application which will read data generated by files written to from the IPython
thread, the safest approach is to open all of your files in unbuffered mode (the
third argument to the file/open function is the buffering value):
filehandle = open(filename,mode,0)
This is obviously a brute force way of avoiding race conditions with the file buffering. If you want to do it cleanly, and you have a resource which is being shared by the interactive IPython loop and your GUI thread, you should really handle it with thread locking and syncrhonization properties. The Python documentation discusses these.
Fernando Perez 2006-06-06