##// END OF EJS Templates
Add design doc about core module.
Fernando Perez -
Show More
@@ -0,0 +1,149 b''
1 ========================================
2 Design proposal for mod:`IPython.core`
3 ========================================
4
5 Currently mod:`IPython.core` is not well suited for use in GUI
6 applications. The purpose of this document is to describe a design that will
7 resolve this limitation.
8
9 Process and thread model
10 ========================
11
12 The design described here is based on a two process model. These two processes
13 are:
14
15 1. The IPython engine/kernel. This process contains the user's namespace and is
16 responsible for executing user code. If user code uses
17 :mod:`enthought.traits` or uses a GUI toolkit to perform plotting, the GUI
18 event loop will run in this process.
19
20 2. The GUI application. The user facing GUI application will run in a second
21 process that communicates directly with the IPython engine using a suitable
22 RPC mechanism. The GUI application will not execute any user code. The
23 canonical example of a GUI application that talks to the IPython engine,
24 would be a GUI based IPython terminal. However, the GUI application could
25 provide a more sophisticated interface such as a notebook.
26
27 We now describe the treading model of the IPython engine. Two threads will be
28 used to implement the IPython engine: a main thread that executes user code and
29 a networking thread that communicates with the outside world. This specific
30 design is required by a number of different factors.
31
32 First, The IPython engine must run the GUI event loop if the user wants to
33 perform interactive plotting. Because of the design of most GUIs, this means
34 that the user code (which will make GUI calls) must live in the main thread.
35
36 Second, networking code in the engine (Twisted or otherwise) must be able to
37 communicate with the outside world while user code runs. An example would be if
38 user code does the following::
39
40 import time
41 for i in range(10):
42 print i
43 time.sleep(2)
44
45 We would like to result of each ``print i`` to be seen by the GUI application
46 before the entire code block completes. We call this asynchronous printing.
47 For this to be possible, the networking code has to be able to be able to
48 communicate the value of ``stdout`` to the GUI application while user code is
49 run. Another example is using :mod:`IPython.kernel.client` in user code to
50 perform a parallel computation by talking to an IPython controller and a set of
51 engines (these engines are separate from the one we are discussing here). This
52 module requires the Twisted event loop to be run in a different thread than
53 user code.
54
55 For the GUI application, threads are optional. However, the GUI application
56 does need to be able to perform network communications asynchronously (without
57 blocking the GUI itself). With this in mind, there are two options:
58
59 * Use Twisted (or another non-blocking socket library) in the same thread as
60 the GUI event loop.
61
62 * Don't use Twisted, but instead run networking code in the GUI application
63 using blocking sockets in threads. This would require the usage of polling
64 and queues to manage the networking in the GUI application.
65
66 Thus, for the GUI application, there is a choice between non-blocking sockets
67 (Twisted) or threads.
68
69 Interprocess communication
70 ==========================
71
72 The GUI application will use interprocess communication (IPC) to communicate
73 with the networking thread of the engine. Because this communication will
74 typically happen over localhost, a simple, one way, non-secure protocol like
75 XML-RPC or JSON-RPC can be used. These options will also make it easy to
76 implement the required networking in the GUI application using the standard
77 library. In applications where secure communications are required, Twisted and
78 Foolscap will probably be the best way to go for now.
79
80 Using this communication channel, the GUI application will be able to perform
81 the following actions with the engine:
82
83 * Pass code (as a string) to be executed by the engine in the user's namespace
84 as a string.
85
86 * Get the current value of stdout and stderr.
87
88 * Pass a string to the engine to be completed when the GUI application
89 receives a tab completion event.
90
91 * Get a list of all variable names in the user's namespace.
92
93 * Other similar actions.
94
95 Engine details
96 ==============
97
98 As discussed above, the engine will consist of two threads: a main thread and a
99 networking thread. These two threads will communicate using a pair of queues:
100 one for data and requests passing to the main thread (the main thread's "input
101 queue") and another for data and requests passing out of the main thread (the
102 main thread's "output queue"). Both threads will have an event loop that will
103 enqueue elements on one queue and dequeue elements on the other queue.
104
105 The event loop of the main thread will be of a different nature depending on if
106 the user wants to perform interactive plotting. If they do want to perform
107 interactive plotting, the main threads event loop will simply be the GUI event
108 loop. In that case, GUI timers will be used to monitor the main threads input
109 queue. When elements appear on that queue, the main thread will respond
110 appropriately. For example, if the queue contains an element that consists of
111 user code to execute, the main thread will call the appropriate method of its
112 IPython instance. If the user does not want to perform interactive plotting,
113 the main thread will have a simpler event loop that will simply block on the
114 input queue. When something appears on that queue, the main thread will awake
115 and handle the request.
116
117 The event loop of the networking thread will typically be the Twisted event
118 loop. While it is possible to implement the engine's networking without using
119 Twisted, at this point, Twisted provides the best solution. Note that the GUI
120 application does not need to use Twisted in this case. The Twisted event loop
121 will contain an XML-RPC or JSON-RPC server that takes requests over the network
122 and handles those requests by enqueing elements on the main thread's input
123 queue or dequeing elements on the main thread's output queue.
124
125 Because of the asynchronous nature of the network communication, a single input
126 and output queue will be used to handle the interaction with the main
127 thread. It is also possible to use multiple queues to isolate the different
128 types of requests, but our feeling is that this is more complicated than it
129 needs to be.
130
131 One of the main issues is how stdout/stderr will be handled. Our idea is to
132 replace sys.stdout/sys.stderr by custom classes that will immediately write
133 data to the main thread's output queue when user code writes to these streams
134 (by doing print). Once on the main thread's output queue, the networking thread
135 will make the data available to the GUI application over the network.
136
137 One unavoidable limitation in this design is that if user code does a print and
138 then enters non-GIL-releasing extension code, the networking thread will go
139 silent until the GIL is again released. During this time, the networking thread
140 will not be able to process the GUI application's requests of the engine. Thus,
141 the values of stdout/stderr will be unavailable during this time. This goes
142 beyond stdout/stderr, however. Anytime the main thread is holding the GIL, the
143 networking thread will go silent and be unable to handle requests.
144
145 Refactoring of IPython.core
146 ===========================
147
148 We need to go through IPython.core and describe what specifically needs to be
149 done.
General Comments 0
You need to be logged in to leave comments. Login now