-
Notifications
You must be signed in to change notification settings - Fork 19
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;
-
shellgets a message and starts running user code. -
iopubgets messages from user code (iesend_mime) and monitors stdout and stderr for activity and sends messages to the notebook for display. - The code finishes.
iopubis told to flush. The notebook is told we are done. - Repeat.