Run a DataFlow in >=1 processes, with ZeroMQ for communication. It will fork the calling process of :meth:`reset_state()`, and collect datapoints from the given dataflow in each process by ZeroMQ IPC pipe. This is typically faster than :class:`MultiProcessRunner`. Note:
| 239 | |
| 240 | |
| 241 | class MultiProcessRunnerZMQ(_MultiProcessZMQDataFlow): |
| 242 | """ |
| 243 | Run a DataFlow in >=1 processes, with ZeroMQ for communication. |
| 244 | It will fork the calling process of :meth:`reset_state()`, |
| 245 | and collect datapoints from the given dataflow in each process by ZeroMQ IPC pipe. |
| 246 | This is typically faster than :class:`MultiProcessRunner`. |
| 247 | |
| 248 | Note: |
| 249 | 1. (Data integrity) An iterator cannot run faster automatically -- what's happening is |
| 250 | that the process will be forked ``num_proc`` times. |
| 251 | There will be ``num_proc`` dataflow running in parallel and **independently**. |
| 252 | As a result, we have the following guarantee on the dataflow correctness: |
| 253 | |
| 254 | a. When ``num_proc=1``, this dataflow produces the same data as the |
| 255 | given dataflow in the same order. |
| 256 | b. When ``num_proc>1``, if each sample from the given dataflow is i.i.d., |
| 257 | then this dataflow produces the **same distribution** of data as the given dataflow. |
| 258 | This implies that there will be duplication, reordering, etc. |
| 259 | You probably only want to use it for training. |
| 260 | |
| 261 | For example, if your original dataflow contains no randomness and produces the same first datapoint, |
| 262 | then after parallel prefetching, the datapoint will be produced ``num_proc`` times |
| 263 | at the beginning. |
| 264 | Even when your original dataflow is fully shuffled, you still need to be aware of the |
| 265 | `Birthday Paradox <https://en.wikipedia.org/wiki/Birthday_problem>`_ |
| 266 | and know that you'll likely see duplicates. |
| 267 | |
| 268 | To utilize parallelism with more strict data integrity, you can use |
| 269 | the parallel versions of :class:`MapData`: :class:`MultiThreadMapData`, :class:`MultiProcessMapData`. |
| 270 | 2. `reset_state()` of the given dataflow will be called **once and only once** in the worker processes. |
| 271 | 3. The fork of processes happened in this dataflow's `reset_state()` method. |
| 272 | Please note that forking a TensorFlow GPU session may be unsafe. |
| 273 | If you're managing this dataflow on your own, |
| 274 | it's better to fork before creating the session. |
| 275 | 4. (Fork-safety) After the fork has happened, this dataflow becomes not fork-safe. |
| 276 | i.e., if you fork an already reset instance of this dataflow, |
| 277 | it won't be usable in the forked process. Therefore, do not nest two `MultiProcessRunnerZMQ`. |
| 278 | 5. (Thread-safety) ZMQ is not thread safe. Therefore, do not call :meth:`get_data` of the same dataflow in |
| 279 | more than 1 threads. |
| 280 | 6. This dataflow does not support windows. Use `MultiProcessRunner` which works on windows. |
| 281 | 7. (For Mac only) A UNIX named pipe will be created in the current directory. |
| 282 | However, certain non-local filesystem such as NFS/GlusterFS/AFS doesn't always support pipes. |
| 283 | You can change the directory by ``export TENSORPACK_PIPEDIR=/other/dir``. |
| 284 | In particular, you can use somewhere under '/tmp' which is usually local. |
| 285 | |
| 286 | Note that some non-local FS may appear to support pipes and code |
| 287 | may appear to run but crash with bizarre error. |
| 288 | Also note that ZMQ limits the maximum length of pipe path. |
| 289 | If you hit the limit, you can set the directory to a softlink |
| 290 | which points to a local directory. |
| 291 | """ |
| 292 | |
| 293 | class _Worker(mp.Process): |
| 294 | def __init__(self, ds, conn_name, hwm, idx): |
| 295 | super(MultiProcessRunnerZMQ._Worker, self).__init__() |
| 296 | self.ds = ds |
| 297 | self.conn_name = conn_name |
| 298 | self.hwm = hwm |
no outgoing calls
no test coverage detected