|
1 | 1 | # Multi-threading |
2 | 2 |
|
3 | | -Perspective's API is thread-safe (safe to call from multiple threads |
4 | | -concurrently), |
| 3 | +Perspective's API is thread-safe, so methods may be called from different |
| 4 | +threads without additional consideration for safety/exclusivity/correctness. All |
| 5 | +`perspective.Client` and `perspective.Server` API methods release the GIL, which |
| 6 | +can be exploited for parallelism. |
5 | 7 |
|
6 | | -Perspective's server API releases the GIL when called (though it may be retained |
7 | | -for some portion of the `Client` call to encode RPC messages). It also |
8 | | -dispatches to an internal thread pool for some operations, enabling better |
9 | | -parallelism and overall better server performance. However, Perspective's Python |
10 | | -interface itself will still process queries in a single queue. To enable |
11 | | -parallel query processing, call `set_loop_callback` with a multi-threaded |
12 | | -executor such as `concurrent.futures.ThreadPoolExecutor`: |
| 8 | +Interally, `perspective.Server` also dispatches to a thread pool for some |
| 9 | +operations, enabling better parallelism and overall better query performance. |
| 10 | +This independent threadpool size can be controlled via |
| 11 | +`perspective.set_num_cpus()`, or the `OMP_NUM_THREADS` environment variable. |
13 | 12 |
|
14 | 13 | ```python |
15 | | -def perspective_thread(): |
16 | | - server = perspective.Server() |
17 | | - loop = tornado.ioloop.IOLoop() |
18 | | - with concurrent.futures.ThreadPoolExecutor() as executor: |
19 | | - server.set_loop_callback(loop.run_in_executor, executor) |
20 | | - loop.start() |
| 14 | +import perspective |
| 15 | + |
| 16 | +perspective.set_num_cpus(2) |
| 17 | +``` |
| 18 | + |
| 19 | +## Server handlers |
| 20 | + |
| 21 | +Perspective's server handler implementations each take an optional `executor` |
| 22 | +constructor argument, which (when provided) will configure the handler to |
| 23 | +process WebSocket `Client` requests on a thread pool. |
| 24 | + |
| 25 | +```python |
| 26 | +from concurrent.futures import ThreadPoolExecutor |
| 27 | +from tornado.web import Application |
| 28 | +from perspective.handlers.tornado import PerspectiveTornadoHandler |
| 29 | +from perspective import Server |
| 30 | + |
| 31 | +args = {"perspective_server": Server(), "executor": ThreadPoolExecutor()} |
| 32 | + |
| 33 | +app = Application( |
| 34 | + [ |
| 35 | + (r"/websocket", PerspectiveTornadoHandler, args), |
| 36 | + |
| 37 | + # ... |
| 38 | + |
| 39 | + ] |
| 40 | +) |
21 | 41 | ``` |
0 commit comments