From 4e6327493dad16acad922fade50c23404ebb4531 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Fri, 10 Apr 2020 18:57:37 -0700 Subject: [PATCH 1/5] Support SO_REUSEPORT on manylinux2010 --- src/core/lib/iomgr/socket_utils_common_posix.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc index a5048d890d3..f368cb76f62 100644 --- a/src/core/lib/iomgr/socket_utils_common_posix.cc +++ b/src/core/lib/iomgr/socket_utils_common_posix.cc @@ -210,7 +210,6 @@ static gpr_once g_probe_so_reuesport_once = GPR_ONCE_INIT; static int g_support_so_reuseport = false; void probe_so_reuseport_once(void) { -#ifndef GPR_MANYLINUX1 int s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { /* This might be an ipv6-only environment in which case 'socket(AF_INET,..)' @@ -222,7 +221,6 @@ void probe_so_reuseport_once(void) { "check for SO_REUSEPORT", grpc_set_socket_reuse_port(s, 1)); close(s); } -#endif } bool grpc_is_socket_reuse_port_supported() { From 96024a9ad30c9863f7a94716ba79e6f087368067 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Fri, 10 Apr 2020 19:22:55 -0700 Subject: [PATCH 2/5] Update documentation --- examples/python/multiprocessing/README.md | 17 ++++++++--------- examples/python/multiprocessing/server.py | 6 ------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/examples/python/multiprocessing/README.md b/examples/python/multiprocessing/README.md index 709a815aca5..19cc00b6a4e 100644 --- a/examples/python/multiprocessing/README.md +++ b/examples/python/multiprocessing/README.md @@ -1,16 +1,19 @@ ## Multiprocessing with gRPC Python Multiprocessing allows application developers to sidestep the Python global -interpreter lock and achieve true concurrency on multicore systems. +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`](http://man7.org/linux/man-pages/man2/fork.2.html), much of the -state copied into the child process is invalid, leading to hangs and crashes. +[`fork`](http://man7.org/linux/man-pages/man2/fork.2.html), any threads in a +critical section may leave the state of the gRPC library invalid in the child +process. See this [excellent research +paper](https://www.microsoft.com/en-us/research/uploads/prod/2019/04/fork-hotos19.pdf) +for a thorough discussion of the topic. -However, calling `fork` without `exec` in your python process is supported +Ccalling `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. @@ -18,11 +21,7 @@ take advantage of this to parallelize their CPU-intensive operations. 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`](https://lwn.net/Articles/542629/) socket option. Note that this -option is not available in `manylinux1` distributions, which are, as of the time -of writing, the only gRPC Python wheels available on PyPI. To take advantage of this -feature, you'll need to build from source, either using bazel (as we do for -these examples) or via pip, using `pip install grpcio --no-binary grpcio`. +[`SO_REUSEPORT`](https://lwn.net/Articles/542629/) socket option. ```python _PROCESS_COUNT = multiprocessing.cpu_count() diff --git a/examples/python/multiprocessing/server.py b/examples/python/multiprocessing/server.py index ad788b8eb51..74a8860119f 100644 --- a/examples/python/multiprocessing/server.py +++ b/examples/python/multiprocessing/server.py @@ -67,12 +67,6 @@ def _run_server(bind_address): _LOGGER.info('Starting new server.') options = (('grpc.so_reuseport', 1),) - # WARNING: This example takes advantage of SO_REUSEPORT. Due to the - # limitations of manylinux1, none of our precompiled Linux wheels currently - # support this option. (https://github.com/grpc/grpc/issues/18210). To take - # advantage of this feature, install from source with - # `pip install grpcio --no-binary grpcio`. - server = grpc.server(futures.ThreadPoolExecutor( max_workers=_THREAD_CONCURRENCY,), options=options) From e97cd37e68c49504af71429bd0a3083f17aedd17 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Fri, 10 Apr 2020 19:33:07 -0700 Subject: [PATCH 3/5] Support running multiprocessing example without Bazel --- examples/python/multiprocessing/BUILD | 2 ++ examples/python/multiprocessing/README.md | 8 ++++++++ examples/python/multiprocessing/client.py | 4 ++-- examples/python/multiprocessing/server.py | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/examples/python/multiprocessing/BUILD b/examples/python/multiprocessing/BUILD index ea9b6a3ec6f..1ee3b647ae4 100644 --- a/examples/python/multiprocessing/BUILD +++ b/examples/python/multiprocessing/BUILD @@ -44,6 +44,7 @@ py_binary( ":prime_proto_pb2_grpc", "//src/python/grpcio/grpc:grpcio", ], + imports = ["."], ) py_binary( @@ -60,6 +61,7 @@ py_binary( "//conditions:default": ["@futures//:futures"], "//:python3": [], }), + imports = ["."], ) py_test( diff --git a/examples/python/multiprocessing/README.md b/examples/python/multiprocessing/README.md index 19cc00b6a4e..a800190682f 100644 --- a/examples/python/multiprocessing/README.md +++ b/examples/python/multiprocessing/README.md @@ -64,3 +64,11 @@ For example, ``` bazel run //examples/python/multiprocessing:client -- [::]:33915 ``` + +Alternatively, generate code using the following and then run the client and server +directly: + +```python +cd examples/python/helloworld +python -m grpc_tools.protoc -I . prime.proto --python_out=. --grpc_python_out=. +``` diff --git a/examples/python/multiprocessing/client.py b/examples/python/multiprocessing/client.py index b9acc65fdc5..7676bd4ec88 100644 --- a/examples/python/multiprocessing/client.py +++ b/examples/python/multiprocessing/client.py @@ -26,8 +26,8 @@ import sys import grpc -from examples.python.multiprocessing import prime_pb2 -from examples.python.multiprocessing import prime_pb2_grpc +import prime_pb2 +import prime_pb2_grpc _PROCESS_COUNT = 8 _MAXIMUM_CANDIDATE = 10000 diff --git a/examples/python/multiprocessing/server.py b/examples/python/multiprocessing/server.py index 74a8860119f..a5ee00755e6 100644 --- a/examples/python/multiprocessing/server.py +++ b/examples/python/multiprocessing/server.py @@ -29,8 +29,8 @@ import sys import grpc -from examples.python.multiprocessing import prime_pb2 -from examples.python.multiprocessing import prime_pb2_grpc +import prime_pb2 +import prime_pb2_grpc _LOGGER = logging.getLogger(__name__) From c14fce7ab4e25c39639a306ca2ed54e0cf56f3fd Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Fri, 10 Apr 2020 19:35:01 -0700 Subject: [PATCH 4/5] Typo --- examples/python/multiprocessing/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/python/multiprocessing/README.md b/examples/python/multiprocessing/README.md index a800190682f..5dce50ad3bd 100644 --- a/examples/python/multiprocessing/README.md +++ b/examples/python/multiprocessing/README.md @@ -13,8 +13,8 @@ process. See this [excellent research paper](https://www.microsoft.com/en-us/research/uploads/prod/2019/04/fork-hotos19.pdf) for a thorough discussion of the topic. -Ccalling `fork` without `exec` in your process *is* supported -*before* any gRPC servers have been instantiated. Application developers can +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 From 0cdffa970c1ad18fb77cb97cec18a236cfbfbf9d Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Mon, 13 Apr 2020 10:25:56 -0700 Subject: [PATCH 5/5] Buildifier --- examples/python/multiprocessing/BUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/python/multiprocessing/BUILD b/examples/python/multiprocessing/BUILD index 1ee3b647ae4..1d831e729b4 100644 --- a/examples/python/multiprocessing/BUILD +++ b/examples/python/multiprocessing/BUILD @@ -37,6 +37,7 @@ py_binary( name = "client", testonly = 1, srcs = ["client.py"], + imports = ["."], python_version = "PY3", srcs_version = "PY3", deps = [ @@ -44,13 +45,13 @@ py_binary( ":prime_proto_pb2_grpc", "//src/python/grpcio/grpc:grpcio", ], - imports = ["."], ) py_binary( name = "server", testonly = 1, srcs = ["server.py"], + imports = ["."], python_version = "PY3", srcs_version = "PY3", deps = [ @@ -61,7 +62,6 @@ py_binary( "//conditions:default": ["@futures//:futures"], "//:python3": [], }), - imports = ["."], ) py_test(