Sergii Tkachenko
de6ed9ba9f
- Switched from yapf to black - Reconfigure isort for black - Resolve black/pylint idiosyncrasies Note: I used `--experimental-string-processing` because black was producing "implicit string concatenation", similar to what described here: https://github.com/psf/black/issues/1837. While currently this feature is experimental, it will be enabled by default: https://github.com/psf/black/issues/2188. After running black with the new string processing so that the generated code merges these `"hello" " world"` strings concatenations, then I removed `--experimental-string-processing` for stability, and regenerated the code again. To the reviewer: don't even try to open "Files Changed" tab 😄 It's better to review commit-by-commit, and ignore `run black and isort`. |
2 years ago | |
---|---|---|
.. | ||
test | [Python] Migrate from yapf to black (#33138) | 2 years ago |
BUILD | Remove enum and future (#31381) | 2 years ago |
README.md | Fix typo in multiprocessing example Readme (#30132) | 2 years ago |
client.py | [Python] Migrate from yapf to black (#33138) | 2 years ago |
prime.proto | Add basic multiprocessing-based server | 6 years ago |
server.py | [Python] Migrate from yapf to black (#33138) | 2 years ago |
README.md
Multiprocessing with gRPC Python
Multiprocessing allows application developers to sidestep the Python global
interpreter lock and achieve true parallelism on multicore systems.
Unfortunately, using multiprocessing and gRPC Python is not yet as simple as
instantiating your server with a futures.ProcessPoolExecutor
.
The library is implemented as a C extension, maintaining much of the state that
drives the system in native code. As such, upon calling
fork
, any threads in a
critical section may leave the state of the gRPC library invalid in the child
process. See this excellent research
paper
for a thorough discussion of the topic.
Calling fork
without exec
in your process is supported
before any gRPC servers have been instantiated. Application developers can
take advantage of this to parallelize their CPU-intensive operations.
Calculating Prime Numbers with Multiple Processes
This example calculates the first 10,000 prime numbers as an RPC. We instantiate
one server per subprocess, balancing requests between the servers using the
SO_REUSEPORT
socket option.
_PROCESS_COUNT = multiprocessing.cpu_count()
On the server side, we detect the number of CPUs available on the system and spawn exactly that many child processes. If we spin up fewer, we won't be taking full advantage of the hardware resources available.
Running the Example
To run the server,
ensure bazel
is installed
and run:
bazel run //examples/python/multiprocessing:server &
Note the address at which the server is running. For example,
...
[PID 107153] Binding to '[::]:33915'
[PID 107507] Starting new server.
[PID 107508] Starting new server.
...
Note that several servers have been started, each with its own PID.
Now, start the client by running
bazel run //examples/python/multiprocessing:client -- [SERVER_ADDRESS]
For example,
bazel run //examples/python/multiprocessing:client -- [::]:33915
Alternatively, generate code using the following and then run the client and server directly:
cd examples/python/multiprocessing
python -m grpc_tools.protoc -I . prime.proto --python_out=. --grpc_python_out=.