Show More
@@ -1,368 +1,367 b'' | |||||
1 | .. _parallel_messages: |
|
1 | .. _parallel_messages: | |
2 |
|
2 | |||
3 | Messaging for Parallel Computing |
|
3 | Messaging for Parallel Computing | |
4 | ================================ |
|
4 | ================================ | |
5 |
|
5 | |||
6 | This is an extension of the :ref:`messaging <messaging>` doc. Diagrams of the connections |
|
6 | This is an extension of the :ref:`messaging <messaging>` doc. Diagrams of the connections | |
7 | can be found in the :ref:`parallel connections <parallel_connections>` doc. |
|
7 | can be found in the :ref:`parallel connections <parallel_connections>` doc. | |
8 |
|
8 | |||
9 |
|
9 | |||
10 | ZMQ messaging is also used in the parallel computing IPython system. All messages to/from |
|
10 | ZMQ messaging is also used in the parallel computing IPython system. All messages to/from | |
11 | kernels remain the same as the single kernel model, and are forwarded through a ZMQ Queue |
|
11 | kernels remain the same as the single kernel model, and are forwarded through a ZMQ Queue | |
12 | device. The controller receives all messages and replies in these channels, and saves |
|
12 | device. The controller receives all messages and replies in these channels, and saves | |
13 | results for future use. |
|
13 | results for future use. | |
14 |
|
14 | |||
15 | The Controller |
|
15 | The Controller | |
16 | -------------- |
|
16 | -------------- | |
17 |
|
17 | |||
18 | The controller is the central collection of processes in the IPython parallel computing |
|
18 | The controller is the central collection of processes in the IPython parallel computing | |
19 | model. It has two major components: |
|
19 | model. It has two major components: | |
20 |
|
20 | |||
21 | * The Hub |
|
21 | * The Hub | |
22 | * A collection of Schedulers |
|
22 | * A collection of Schedulers | |
23 |
|
23 | |||
24 | The Hub |
|
24 | The Hub | |
25 | ------- |
|
25 | ------- | |
26 |
|
26 | |||
27 | The Hub is the central process for monitoring the state of the engines, and all task |
|
27 | The Hub is the central process for monitoring the state of the engines, and all task | |
28 | requests and results. It has no role in execution and does no relay of messages, so |
|
28 | requests and results. It has no role in execution and does no relay of messages, so | |
29 | large blocking requests or database actions in the Hub do not have the ability to impede |
|
29 | large blocking requests or database actions in the Hub do not have the ability to impede | |
30 | job submission and results. |
|
30 | job submission and results. | |
31 |
|
31 | |||
32 | Registration (``ROUTER``) |
|
32 | Registration (``ROUTER``) | |
33 | *********************** |
|
33 | ************************* | |
34 |
|
34 | |||
35 | The first function of the Hub is to facilitate and monitor connections of clients |
|
35 | The first function of the Hub is to facilitate and monitor connections of clients | |
36 | and engines. Both client and engine registration are handled by the same socket, so only |
|
36 | and engines. Both client and engine registration are handled by the same socket, so only | |
37 | one ip/port pair is needed to connect any number of connections and clients. |
|
37 | one ip/port pair is needed to connect any number of connections and clients. | |
38 |
|
38 | |||
39 | Engines register with the ``zmq.IDENTITY`` of their two ``DEALER`` sockets, one for the |
|
39 | Engines register with the ``zmq.IDENTITY`` of their two ``DEALER`` sockets, one for the | |
40 | queue, which receives execute requests, and one for the heartbeat, which is used to |
|
40 | queue, which receives execute requests, and one for the heartbeat, which is used to | |
41 | monitor the survival of the Engine process. |
|
41 | monitor the survival of the Engine process. | |
42 |
|
42 | |||
43 | Message type: ``registration_request``:: |
|
43 | Message type: ``registration_request``:: | |
44 |
|
44 | |||
45 | content = { |
|
45 | content = { | |
46 | 'uuid' : 'abcd-1234-...', # the zmq.IDENTITY of the engine's sockets |
|
46 | 'uuid' : 'abcd-1234-...', # the zmq.IDENTITY of the engine's sockets | |
47 | } |
|
47 | } | |
48 |
|
48 | |||
49 | .. note:: |
|
49 | .. note:: | |
50 |
|
50 | |||
51 | these are always the same, at least for now. |
|
51 | these are always the same, at least for now. | |
52 |
|
52 | |||
53 | The Controller replies to an Engine's registration request with the engine's integer ID, |
|
53 | The Controller replies to an Engine's registration request with the engine's integer ID, | |
54 | and all the remaining connection information for connecting the heartbeat process, and |
|
54 | and all the remaining connection information for connecting the heartbeat process, and | |
55 | kernel queue socket(s). The message status will be an error if the Engine requests IDs that |
|
55 | kernel queue socket(s). The message status will be an error if the Engine requests IDs that | |
56 | already in use. |
|
56 | already in use. | |
57 |
|
57 | |||
58 | Message type: ``registration_reply``:: |
|
58 | Message type: ``registration_reply``:: | |
59 |
|
59 | |||
60 | content = { |
|
60 | content = { | |
61 | 'status' : 'ok', # or 'error' |
|
61 | 'status' : 'ok', # or 'error' | |
62 | # if ok: |
|
62 | # if ok: | |
63 | 'id' : 0, # int, the engine id |
|
63 | 'id' : 0, # int, the engine id | |
64 | } |
|
64 | } | |
65 |
|
65 | |||
66 | Clients use the same socket as engines to start their connections. Connection requests |
|
66 | Clients use the same socket as engines to start their connections. Connection requests | |
67 | from clients need no information: |
|
67 | from clients need no information: | |
68 |
|
68 | |||
69 | Message type: ``connection_request``:: |
|
69 | Message type: ``connection_request``:: | |
70 |
|
70 | |||
71 | content = {} |
|
71 | content = {} | |
72 |
|
72 | |||
73 | The reply to a Client registration request contains the connection information for the |
|
73 | The reply to a Client registration request contains the connection information for the | |
74 | multiplexer and load balanced queues, as well as the address for direct hub |
|
74 | multiplexer and load balanced queues, as well as the address for direct hub | |
75 | queries. If any of these addresses is `None`, that functionality is not available. |
|
75 | queries. If any of these addresses is `None`, that functionality is not available. | |
76 |
|
76 | |||
77 | Message type: ``connection_reply``:: |
|
77 | Message type: ``connection_reply``:: | |
78 |
|
78 | |||
79 | content = { |
|
79 | content = { | |
80 | 'status' : 'ok', # or 'error' |
|
80 | 'status' : 'ok', # or 'error' | |
81 | } |
|
81 | } | |
82 |
|
82 | |||
83 | Heartbeat |
|
83 | Heartbeat | |
84 | ********* |
|
84 | ********* | |
85 |
|
85 | |||
86 | The hub uses a heartbeat system to monitor engines, and track when they become |
|
86 | The hub uses a heartbeat system to monitor engines, and track when they become | |
87 | unresponsive. As described in :ref:`messaging <messaging>`, and shown in :ref:`connections |
|
87 | unresponsive. As described in :ref:`messaging <messaging>`, and shown in :ref:`connections | |
88 | <parallel_connections>`. |
|
88 | <parallel_connections>`. | |
89 |
|
89 | |||
90 | Notification (``PUB``) |
|
90 | Notification (``PUB``) | |
91 | ********************** |
|
91 | ********************** | |
92 |
|
92 | |||
93 | The hub publishes all engine registration/unregistration events on a ``PUB`` socket. |
|
93 | The hub publishes all engine registration/unregistration events on a ``PUB`` socket. | |
94 | This allows clients to have up-to-date engine ID sets without polling. Registration |
|
94 | This allows clients to have up-to-date engine ID sets without polling. Registration | |
95 | notifications contain both the integer engine ID and the queue ID, which is necessary for |
|
95 | notifications contain both the integer engine ID and the queue ID, which is necessary for | |
96 | sending messages via the Multiplexer Queue and Control Queues. |
|
96 | sending messages via the Multiplexer Queue and Control Queues. | |
97 |
|
97 | |||
98 | Message type: ``registration_notification``:: |
|
98 | Message type: ``registration_notification``:: | |
99 |
|
99 | |||
100 | content = { |
|
100 | content = { | |
101 | 'id' : 0, # engine ID that has been registered |
|
101 | 'id' : 0, # engine ID that has been registered | |
102 | 'uuid' : 'engine_id' # the IDENT for the engine's sockets |
|
102 | 'uuid' : 'engine_id' # the IDENT for the engine's sockets | |
103 | } |
|
103 | } | |
104 |
|
104 | |||
105 | Message type : ``unregistration_notification``:: |
|
105 | Message type : ``unregistration_notification``:: | |
106 |
|
106 | |||
107 | content = { |
|
107 | content = { | |
108 | 'id' : 0 # engine ID that has been unregistered |
|
108 | 'id' : 0 # engine ID that has been unregistered | |
109 | 'uuid' : 'engine_id' # the IDENT for the engine's sockets |
|
109 | 'uuid' : 'engine_id' # the IDENT for the engine's sockets | |
110 | } |
|
110 | } | |
111 |
|
111 | |||
112 |
|
112 | |||
113 | Client Queries (``ROUTER``) |
|
113 | Client Queries (``ROUTER``) | |
114 | ************************* |
|
114 | *************************** | |
115 |
|
115 | |||
116 | The hub monitors and logs all queue traffic, so that clients can retrieve past |
|
116 | The hub monitors and logs all queue traffic, so that clients can retrieve past | |
117 | results or monitor pending tasks. This information may reside in-memory on the Hub, or |
|
117 | results or monitor pending tasks. This information may reside in-memory on the Hub, or | |
118 | on disk in a database (SQLite and MongoDB are currently supported). These requests are |
|
118 | on disk in a database (SQLite and MongoDB are currently supported). These requests are | |
119 | handled by the same socket as registration. |
|
119 | handled by the same socket as registration. | |
120 |
|
120 | |||
121 |
|
121 | |||
122 | :func:`queue_request` requests can specify multiple engines to query via the `targets` |
|
122 | :func:`queue_request` requests can specify multiple engines to query via the `targets` | |
123 | element. A verbose flag can be passed, to determine whether the result should be the list |
|
123 | element. A verbose flag can be passed, to determine whether the result should be the list | |
124 | of `msg_ids` in the queue or simply the length of each list. |
|
124 | of `msg_ids` in the queue or simply the length of each list. | |
125 |
|
125 | |||
126 | Message type: ``queue_request``:: |
|
126 | Message type: ``queue_request``:: | |
127 |
|
127 | |||
128 | content = { |
|
128 | content = { | |
129 | 'verbose' : True, # whether return should be lists themselves or just lens |
|
129 | 'verbose' : True, # whether return should be lists themselves or just lens | |
130 | 'targets' : [0,3,1] # list of ints |
|
130 | 'targets' : [0,3,1] # list of ints | |
131 | } |
|
131 | } | |
132 |
|
132 | |||
133 | The content of a reply to a :func:`queue_request` request is a dict, keyed by the engine |
|
133 | The content of a reply to a :func:`queue_request` request is a dict, keyed by the engine | |
134 | IDs. Note that they will be the string representation of the integer keys, since JSON |
|
134 | IDs. Note that they will be the string representation of the integer keys, since JSON | |
135 | cannot handle number keys. The three keys of each dict are:: |
|
135 | cannot handle number keys. The three keys of each dict are:: | |
136 |
|
136 | |||
137 | 'completed' : messages submitted via any queue that ran on the engine |
|
137 | 'completed' : messages submitted via any queue that ran on the engine | |
138 | 'queue' : jobs submitted via MUX queue, whose results have not been received |
|
138 | 'queue' : jobs submitted via MUX queue, whose results have not been received | |
139 | 'tasks' : tasks that are known to have been submitted to the engine, but |
|
139 | 'tasks' : tasks that are known to have been submitted to the engine, but | |
140 | have not completed. Note that with the pure zmq scheduler, this will |
|
140 | have not completed. Note that with the pure zmq scheduler, this will | |
141 | always be 0/[]. |
|
141 | always be 0/[]. | |
142 |
|
142 | |||
143 | Message type: ``queue_reply``:: |
|
143 | Message type: ``queue_reply``:: | |
144 |
|
144 | |||
145 | content = { |
|
145 | content = { | |
146 | 'status' : 'ok', # or 'error' |
|
146 | 'status' : 'ok', # or 'error' | |
147 | # if verbose=False: |
|
147 | # if verbose=False: | |
148 | '0' : {'completed' : 1, 'queue' : 7, 'tasks' : 0}, |
|
148 | '0' : {'completed' : 1, 'queue' : 7, 'tasks' : 0}, | |
149 | # if verbose=True: |
|
149 | # if verbose=True: | |
150 | '1' : {'completed' : ['abcd-...','1234-...'], 'queue' : ['58008-'], 'tasks' : []}, |
|
150 | '1' : {'completed' : ['abcd-...','1234-...'], 'queue' : ['58008-'], 'tasks' : []}, | |
151 | } |
|
151 | } | |
152 |
|
152 | |||
153 | Clients can request individual results directly from the hub. This is primarily for |
|
153 | Clients can request individual results directly from the hub. This is primarily for | |
154 | gathering results of executions not submitted by the requesting client, as the client |
|
154 | gathering results of executions not submitted by the requesting client, as the client | |
155 | will have all its own results already. Requests are made by msg_id, and can contain one or |
|
155 | will have all its own results already. Requests are made by msg_id, and can contain one or | |
156 | more msg_id. An additional boolean key 'statusonly' can be used to not request the |
|
156 | more msg_id. An additional boolean key 'statusonly' can be used to not request the | |
157 | results, but simply poll the status of the jobs. |
|
157 | results, but simply poll the status of the jobs. | |
158 |
|
158 | |||
159 | Message type: ``result_request``:: |
|
159 | Message type: ``result_request``:: | |
160 |
|
160 | |||
161 | content = { |
|
161 | content = { | |
162 | 'msg_ids' : ['uuid','...'], # list of strs |
|
162 | 'msg_ids' : ['uuid','...'], # list of strs | |
163 | 'targets' : [1,2,3], # list of int ids or uuids |
|
163 | 'targets' : [1,2,3], # list of int ids or uuids | |
164 | 'statusonly' : False, # bool |
|
164 | 'statusonly' : False, # bool | |
165 | } |
|
165 | } | |
166 |
|
166 | |||
167 | The :func:`result_request` reply contains the content objects of the actual execution |
|
167 | The :func:`result_request` reply contains the content objects of the actual execution | |
168 | reply messages. If `statusonly=True`, then there will be only the 'pending' and |
|
168 | reply messages. If `statusonly=True`, then there will be only the 'pending' and | |
169 | 'completed' lists. |
|
169 | 'completed' lists. | |
170 |
|
170 | |||
171 |
|
171 | |||
172 | Message type: ``result_reply``:: |
|
172 | Message type: ``result_reply``:: | |
173 |
|
173 | |||
174 | content = { |
|
174 | content = { | |
175 | 'status' : 'ok', # else error |
|
175 | 'status' : 'ok', # else error | |
176 | # if ok: |
|
176 | # if ok: | |
177 | 'acbd-...' : msg, # the content dict is keyed by msg_ids, |
|
177 | 'acbd-...' : msg, # the content dict is keyed by msg_ids, | |
178 | # values are the result messages |
|
178 | # values are the result messages | |
179 | # there will be none of these if `statusonly=True` |
|
179 | # there will be none of these if `statusonly=True` | |
180 | 'pending' : ['msg_id','...'], # msg_ids still pending |
|
180 | 'pending' : ['msg_id','...'], # msg_ids still pending | |
181 | 'completed' : ['msg_id','...'], # list of completed msg_ids |
|
181 | 'completed' : ['msg_id','...'], # list of completed msg_ids | |
182 | } |
|
182 | } | |
183 | buffers = ['bufs','...'] # the buffers that contained the results of the objects. |
|
183 | buffers = ['bufs','...'] # the buffers that contained the results of the objects. | |
184 | # this will be empty if no messages are complete, or if |
|
184 | # this will be empty if no messages are complete, or if | |
185 | # statusonly is True. |
|
185 | # statusonly is True. | |
186 |
|
186 | |||
187 | For memory management purposes, Clients can also instruct the hub to forget the |
|
187 | For memory management purposes, Clients can also instruct the hub to forget the | |
188 | results of messages. This can be done by message ID or engine ID. Individual messages are |
|
188 | results of messages. This can be done by message ID or engine ID. Individual messages are | |
189 | dropped by msg_id, and all messages completed on an engine are dropped by engine ID. This |
|
189 | dropped by msg_id, and all messages completed on an engine are dropped by engine ID. This | |
190 | may no longer be necessary with the mongodb-based message logging backend. |
|
190 | may no longer be necessary with the mongodb-based message logging backend. | |
191 |
|
191 | |||
192 | If the msg_ids element is the string ``'all'`` instead of a list, then all completed |
|
192 | If the msg_ids element is the string ``'all'`` instead of a list, then all completed | |
193 | results are forgotten. |
|
193 | results are forgotten. | |
194 |
|
194 | |||
195 | Message type: ``purge_request``:: |
|
195 | Message type: ``purge_request``:: | |
196 |
|
196 | |||
197 | content = { |
|
197 | content = { | |
198 | 'msg_ids' : ['id1', 'id2',...], # list of msg_ids or 'all' |
|
198 | 'msg_ids' : ['id1', 'id2',...], # list of msg_ids or 'all' | |
199 | 'engine_ids' : [0,2,4] # list of engine IDs |
|
199 | 'engine_ids' : [0,2,4] # list of engine IDs | |
200 | } |
|
200 | } | |
201 |
|
201 | |||
202 | The reply to a purge request is simply the status 'ok' if the request succeeded, or an |
|
202 | The reply to a purge request is simply the status 'ok' if the request succeeded, or an | |
203 | explanation of why it failed, such as requesting the purge of a nonexistent or pending |
|
203 | explanation of why it failed, such as requesting the purge of a nonexistent or pending | |
204 | message. |
|
204 | message. | |
205 |
|
205 | |||
206 | Message type: ``purge_reply``:: |
|
206 | Message type: ``purge_reply``:: | |
207 |
|
207 | |||
208 | content = { |
|
208 | content = { | |
209 | 'status' : 'ok', # or 'error' |
|
209 | 'status' : 'ok', # or 'error' | |
210 | } |
|
210 | } | |
211 |
|
211 | |||
212 |
|
212 | |||
213 | Schedulers |
|
213 | Schedulers | |
214 | ---------- |
|
214 | ---------- | |
215 |
|
215 | |||
216 | There are three basic schedulers: |
|
216 | There are three basic schedulers: | |
217 |
|
217 | |||
218 | * Task Scheduler |
|
218 | * Task Scheduler | |
219 | * MUX Scheduler |
|
219 | * MUX Scheduler | |
220 | * Control Scheduler |
|
220 | * Control Scheduler | |
221 |
|
221 | |||
222 | The MUX and Control schedulers are simple MonitoredQueue ΓMQ devices, with ``ROUTER`` |
|
222 | The MUX and Control schedulers are simple MonitoredQueue ΓMQ devices, with ``ROUTER`` | |
223 | sockets on either side. This allows the queue to relay individual messages to particular |
|
223 | sockets on either side. This allows the queue to relay individual messages to particular | |
224 | targets via ``zmq.IDENTITY`` routing. The Task scheduler may be a MonitoredQueue ΓMQ |
|
224 | targets via ``zmq.IDENTITY`` routing. The Task scheduler may be a MonitoredQueue ΓMQ | |
225 | device, in which case the client-facing socket is ``ROUTER``, and the engine-facing socket |
|
225 | device, in which case the client-facing socket is ``ROUTER``, and the engine-facing socket | |
226 | is ``DEALER``. The result of this is that client-submitted messages are load-balanced via |
|
226 | is ``DEALER``. The result of this is that client-submitted messages are load-balanced via | |
227 | the ``DEALER`` socket, but the engine's replies to each message go to the requesting client. |
|
227 | the ``DEALER`` socket, but the engine's replies to each message go to the requesting client. | |
228 |
|
228 | |||
229 | Raw ``DEALER`` scheduling is quite primitive, and doesn't allow message introspection, so |
|
229 | Raw ``DEALER`` scheduling is quite primitive, and doesn't allow message introspection, so | |
230 | there are also Python Schedulers that can be used. These Schedulers behave in much the |
|
230 | there are also Python Schedulers that can be used. These Schedulers behave in much the | |
231 | same way as a MonitoredQueue does from the outside, but have rich internal logic to |
|
231 | same way as a MonitoredQueue does from the outside, but have rich internal logic to | |
232 | determine destinations, as well as handle dependency graphs Their sockets are always |
|
232 | determine destinations, as well as handle dependency graphs Their sockets are always | |
233 | ``ROUTER`` on both sides. |
|
233 | ``ROUTER`` on both sides. | |
234 |
|
234 | |||
235 | The Python task schedulers have an additional message type, which informs the Hub of |
|
235 | The Python task schedulers have an additional message type, which informs the Hub of | |
236 | the destination of a task as soon as that destination is known. |
|
236 | the destination of a task as soon as that destination is known. | |
237 |
|
237 | |||
238 | Message type: ``task_destination``:: |
|
238 | Message type: ``task_destination``:: | |
239 |
|
239 | |||
240 | content = { |
|
240 | content = { | |
241 | 'msg_id' : 'abcd-1234-...', # the msg's uuid |
|
241 | 'msg_id' : 'abcd-1234-...', # the msg's uuid | |
242 | 'engine_id' : '1234-abcd-...', # the destination engine's zmq.IDENTITY |
|
242 | 'engine_id' : '1234-abcd-...', # the destination engine's zmq.IDENTITY | |
243 | } |
|
243 | } | |
244 |
|
244 | |||
245 | :func:`apply` and :func:`apply_bound` |
|
245 | :func:`apply` | |
246 | ************************************* |
|
246 | ************* | |
247 |
|
247 | |||
248 | In terms of message classes, the MUX scheduler and Task scheduler relay the exact same |
|
248 | In terms of message classes, the MUX scheduler and Task scheduler relay the exact same | |
249 | message types. Their only difference lies in how the destination is selected. |
|
249 | message types. Their only difference lies in how the destination is selected. | |
250 |
|
250 | |||
251 | The `Namespace <http://gist.github.com/483294>`_ model suggests that execution be able to |
|
251 | The `Namespace <http://gist.github.com/483294>`_ model suggests that execution be able to | |
252 | use the model:: |
|
252 | use the model:: | |
253 |
|
253 | |||
254 | ns.apply(f, *args, **kwargs) |
|
254 | ns.apply(f, *args, **kwargs) | |
255 |
|
255 | |||
256 | which takes `f`, a function in the user's namespace, and executes ``f(*args, **kwargs)`` |
|
256 | which takes `f`, a function in the user's namespace, and executes ``f(*args, **kwargs)`` | |
257 | on a remote engine, returning the result (or, for non-blocking, information facilitating |
|
257 | on a remote engine, returning the result (or, for non-blocking, information facilitating | |
258 | later retrieval of the result). This model, unlike the execute message which just uses a |
|
258 | later retrieval of the result). This model, unlike the execute message which just uses a | |
259 | code string, must be able to send arbitrary (pickleable) Python objects. And ideally, copy |
|
259 | code string, must be able to send arbitrary (pickleable) Python objects. And ideally, copy | |
260 | as little data as we can. The `buffers` property of a Message was introduced for this |
|
260 | as little data as we can. The `buffers` property of a Message was introduced for this | |
261 | purpose. |
|
261 | purpose. | |
262 |
|
262 | |||
263 |
Utility method :func:`build_apply_message` in :mod:`IPython.zmq.s |
|
263 | Utility method :func:`build_apply_message` in :mod:`IPython.zmq.serialize` wraps a | |
264 | function signature and builds a sendable buffer format for minimal data copying (exactly |
|
264 | function signature and builds a sendable buffer format for minimal data copying (exactly | |
265 | zero copies of numpy array data or buffers or large strings). |
|
265 | zero copies of numpy array data or buffers or large strings). | |
266 |
|
266 | |||
267 | Message type: ``apply_request``:: |
|
267 | Message type: ``apply_request``:: | |
268 |
|
268 | |||
269 |
|
|
269 | metadata = { | |
270 | 'bound' : True, # whether to execute in the engine's namespace or unbound |
|
|||
271 | 'after' : ['msg_id',...], # list of msg_ids or output of Dependency.as_dict() |
|
270 | 'after' : ['msg_id',...], # list of msg_ids or output of Dependency.as_dict() | |
272 | 'follow' : ['msg_id',...], # list of msg_ids or output of Dependency.as_dict() |
|
271 | 'follow' : ['msg_id',...], # list of msg_ids or output of Dependency.as_dict() | |
273 |
|
||||
274 | } |
|
272 | } | |
|
273 | content = {} | |||
275 | buffers = ['...'] # at least 3 in length |
|
274 | buffers = ['...'] # at least 3 in length | |
276 | # as built by build_apply_message(f,args,kwargs) |
|
275 | # as built by build_apply_message(f,args,kwargs) | |
277 |
|
276 | |||
278 | after/follow represent task dependencies. 'after' corresponds to a time dependency. The |
|
277 | after/follow represent task dependencies. 'after' corresponds to a time dependency. The | |
279 | request will not arrive at an engine until the 'after' dependency tasks have completed. |
|
278 | request will not arrive at an engine until the 'after' dependency tasks have completed. | |
280 | 'follow' corresponds to a location dependency. The task will be submitted to the same |
|
279 | 'follow' corresponds to a location dependency. The task will be submitted to the same | |
281 | engine as these msg_ids (see :class:`Dependency` docs for details). |
|
280 | engine as these msg_ids (see :class:`Dependency` docs for details). | |
282 |
|
281 | |||
283 | Message type: ``apply_reply``:: |
|
282 | Message type: ``apply_reply``:: | |
284 |
|
283 | |||
285 | content = { |
|
284 | content = { | |
286 | 'status' : 'ok' # 'ok' or 'error' |
|
285 | 'status' : 'ok' # 'ok' or 'error' | |
287 | # other error info here, as in other messages |
|
286 | # other error info here, as in other messages | |
288 | } |
|
287 | } | |
289 | buffers = ['...'] # either 1 or 2 in length |
|
288 | buffers = ['...'] # either 1 or 2 in length | |
290 | # a serialization of the return value of f(*args,**kwargs) |
|
289 | # a serialization of the return value of f(*args,**kwargs) | |
291 | # only populated if status is 'ok' |
|
290 | # only populated if status is 'ok' | |
292 |
|
291 | |||
293 | All engine execution and data movement is performed via apply messages. |
|
292 | All engine execution and data movement is performed via apply messages. | |
294 |
|
293 | |||
295 | Control Messages |
|
294 | Control Messages | |
296 | ---------------- |
|
295 | ---------------- | |
297 |
|
296 | |||
298 | Messages that interact with the engines, but are not meant to execute code, are submitted |
|
297 | Messages that interact with the engines, but are not meant to execute code, are submitted | |
299 | via the Control queue. These messages have high priority, and are thus received and |
|
298 | via the Control queue. These messages have high priority, and are thus received and | |
300 | handled before any execution requests. |
|
299 | handled before any execution requests. | |
301 |
|
300 | |||
302 | Clients may want to clear the namespace on the engine. There are no arguments nor |
|
301 | Clients may want to clear the namespace on the engine. There are no arguments nor | |
303 | information involved in this request, so the content is empty. |
|
302 | information involved in this request, so the content is empty. | |
304 |
|
303 | |||
305 | Message type: ``clear_request``:: |
|
304 | Message type: ``clear_request``:: | |
306 |
|
305 | |||
307 | content = {} |
|
306 | content = {} | |
308 |
|
307 | |||
309 | Message type: ``clear_reply``:: |
|
308 | Message type: ``clear_reply``:: | |
310 |
|
309 | |||
311 | content = { |
|
310 | content = { | |
312 | 'status' : 'ok' # 'ok' or 'error' |
|
311 | 'status' : 'ok' # 'ok' or 'error' | |
313 | # other error info here, as in other messages |
|
312 | # other error info here, as in other messages | |
314 | } |
|
313 | } | |
315 |
|
314 | |||
316 | Clients may want to abort tasks that have not yet run. This can by done by message id, or |
|
315 | Clients may want to abort tasks that have not yet run. This can by done by message id, or | |
317 | all enqueued messages can be aborted if None is specified. |
|
316 | all enqueued messages can be aborted if None is specified. | |
318 |
|
317 | |||
319 | Message type: ``abort_request``:: |
|
318 | Message type: ``abort_request``:: | |
320 |
|
319 | |||
321 | content = { |
|
320 | content = { | |
322 | 'msg_ids' : ['1234-...', '...'] # list of msg_ids or None |
|
321 | 'msg_ids' : ['1234-...', '...'] # list of msg_ids or None | |
323 | } |
|
322 | } | |
324 |
|
323 | |||
325 | Message type: ``abort_reply``:: |
|
324 | Message type: ``abort_reply``:: | |
326 |
|
325 | |||
327 | content = { |
|
326 | content = { | |
328 | 'status' : 'ok' # 'ok' or 'error' |
|
327 | 'status' : 'ok' # 'ok' or 'error' | |
329 | # other error info here, as in other messages |
|
328 | # other error info here, as in other messages | |
330 | } |
|
329 | } | |
331 |
|
330 | |||
332 | The last action a client may want to do is shutdown the kernel. If a kernel receives a |
|
331 | The last action a client may want to do is shutdown the kernel. If a kernel receives a | |
333 | shutdown request, then it aborts all queued messages, replies to the request, and exits. |
|
332 | shutdown request, then it aborts all queued messages, replies to the request, and exits. | |
334 |
|
333 | |||
335 | Message type: ``shutdown_request``:: |
|
334 | Message type: ``shutdown_request``:: | |
336 |
|
335 | |||
337 | content = {} |
|
336 | content = {} | |
338 |
|
337 | |||
339 | Message type: ``shutdown_reply``:: |
|
338 | Message type: ``shutdown_reply``:: | |
340 |
|
339 | |||
341 | content = { |
|
340 | content = { | |
342 | 'status' : 'ok' # 'ok' or 'error' |
|
341 | 'status' : 'ok' # 'ok' or 'error' | |
343 | # other error info here, as in other messages |
|
342 | # other error info here, as in other messages | |
344 | } |
|
343 | } | |
345 |
|
344 | |||
346 |
|
345 | |||
347 | Implementation |
|
346 | Implementation | |
348 | -------------- |
|
347 | -------------- | |
349 |
|
348 | |||
350 | There are a few differences in implementation between the `StreamSession` object used in |
|
349 | There are a few differences in implementation between the `StreamSession` object used in | |
351 | the newparallel branch and the `Session` object, the main one being that messages are |
|
350 | the newparallel branch and the `Session` object, the main one being that messages are | |
352 | sent in parts, rather than as a single serialized object. `StreamSession` objects also |
|
351 | sent in parts, rather than as a single serialized object. `StreamSession` objects also | |
353 | take pack/unpack functions, which are to be used when serializing/deserializing objects. |
|
352 | take pack/unpack functions, which are to be used when serializing/deserializing objects. | |
354 | These can be any functions that translate to/from formats that ZMQ sockets can send |
|
353 | These can be any functions that translate to/from formats that ZMQ sockets can send | |
355 | (buffers,bytes, etc.). |
|
354 | (buffers,bytes, etc.). | |
356 |
|
355 | |||
357 | Split Sends |
|
356 | Split Sends | |
358 | *********** |
|
357 | *********** | |
359 |
|
358 | |||
360 | Previously, messages were bundled as a single json object and one call to |
|
359 | Previously, messages were bundled as a single json object and one call to | |
361 | :func:`socket.send_json`. Since the hub inspects all messages, and doesn't need to |
|
360 | :func:`socket.send_json`. Since the hub inspects all messages, and doesn't need to | |
362 | see the content of the messages, which can be large, messages are now serialized and sent in |
|
361 | see the content of the messages, which can be large, messages are now serialized and sent in | |
363 |
pieces. All messages are sent in at least |
|
362 | pieces. All messages are sent in at least 4 parts: the header, the parent header, the metadata and the content. | |
364 |
|
|
363 | This allows the controller to unpack and inspect the (always small) header, | |
365 | without spending time unpacking the content unless the message is bound for the |
|
364 | without spending time unpacking the content unless the message is bound for the | |
366 | controller. Buffers are added on to the end of the message, and can be any objects that |
|
365 | controller. Buffers are added on to the end of the message, and can be any objects that | |
367 | present the buffer interface. |
|
366 | present the buffer interface. | |
368 |
|
367 |
General Comments 0
You need to be logged in to leave comments.
Login now