-
Notifications
You must be signed in to change notification settings - Fork 20
Architecture
This is my best guess for how things works in IPython.
There are three main things involved when IOcaml starts.
- Notebook - runs a user interface and talks over websockets to IPython.
- IPython - runs the webserver. All communications between IOCaml and the notebook go through IPython.
- IOCaml - talks to IPython through ZeroMQ messages. IPython also sends signals to IOCaml in certain cases.
I am a little unsure exactly how much work IPython is doing apart from being a webserver and a bridge for messaging.
IOCaml needs to run the REPL, respond to messages from the notebook and generate messages back to the notebook. The very first version of IOCaml did this;
- Wait for code execution message from the notebook.
- Run the code.
- Collect up all the responses (from stdout, stderr and the compiler messages) and send them to the notebook.
I soon noticed an issue - if you write a few Kb to stdout the REPL will lockup on the next write. A fair enough point, the out_channel is buffered and full. So, we need to run I/O concurrently with code execution.
This is possible because user code I/O and kernel messages are run on different zeromq sockets. There are basically two important sockets here shell
and iopub
. The shell
socket mainly controls code execution (and IOCaml). The iopub
socket deals with all the responses.
What we do is start a thread to deal with the iopub
socket. The main thread just deals with shell
messages. The two threads communicate through Marshalled messages over a Unix.pipe.
There is still a distinct execution flow going on;
-
shell
gets a message and starts running user code. -
iopub
gets messages from user code (iesend_mime
) and monitors stdout and stderr for activity and sends messages to the notebook for display. - The code finishes.
iopub
is told to flush. The notebook is told we are done. - Repeat.