chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Multi-threading
|
||||
|
||||
Perspective's API is thread-safe, so methods may be called from different
|
||||
threads without additional consideration for safety/exclusivity/correctness. All
|
||||
`perspective.Client` and `perspective.Server` API methods release the GIL, which
|
||||
can be exploited for parallelism.
|
||||
|
||||
Interally, `perspective.Server` also dispatches to a thread pool for some
|
||||
operations, enabling better parallelism and overall better query performance.
|
||||
This independent threadpool size can be controlled via
|
||||
`perspective.set_num_cpus()`, or the `OMP_NUM_THREADS` environment variable.
|
||||
|
||||
```python
|
||||
import perspective
|
||||
|
||||
perspective.set_num_cpus(2)
|
||||
```
|
||||
|
||||
## Server handlers
|
||||
|
||||
Perspective's server handler implementations each take an optional `executor`
|
||||
constructor argument, which (when provided) will configure the handler to
|
||||
process WebSocket `Client` requests on a thread pool.
|
||||
|
||||
```python
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from tornado.web import Application
|
||||
from perspective.handlers.tornado import PerspectiveTornadoHandler
|
||||
from perspective import Server
|
||||
|
||||
args = {"perspective_server": Server(), "executor": ThreadPoolExecutor()}
|
||||
|
||||
app = Application(
|
||||
[
|
||||
(r"/websocket", PerspectiveTornadoHandler, args),
|
||||
|
||||
# ...
|
||||
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
## `on_poll_request`
|
||||
|
||||
`on_poll_request` is an optional keyword argument for `Server()`, which which
|
||||
can be applied in cases where overlapping `Table.update` calls can be safely
|
||||
deferred.
|
||||
|
||||
When providing a callback function to `on_poll_request`, the `Server` will
|
||||
invoke your callback when there are updates that need to be flushed, after which
|
||||
you must _eventually_ call `Server.poll` (or else no updates will be processed).
|
||||
|
||||
The exact implementation of `on_poll_request` will depend on the context. A
|
||||
simple example which batches calls via `threading.Lock`:
|
||||
|
||||
```python
|
||||
lock = threading.Lock()
|
||||
|
||||
def on_poll_request(perspective_server):
|
||||
if lock.acquire(blocking=False):
|
||||
try:
|
||||
perspective_server.poll()
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
server = Server(on_poll_request=on_poll_request)
|
||||
```
|
||||
Reference in New Issue
Block a user