New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core: don't wrap sequential executors in ClientCallImpl and ServerImpl #5521
base: master
Are you sure you want to change the base?
Conversation
private static final Class<? extends Executor> guavaSeqExecutorClass; | ||
|
||
static { | ||
boolean wrapSerialized = Boolean.getBoolean("grpc.wrapSerialized"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is here to make the benchmark comparisons easier, can be tidied up if this is accepted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a sequential executor on server-side seems a bit bizarre, as that limits you to one thread for all RPCs. And if anything I'd see it as being more likely to be a single-thread thread pool. Sequential executor on client-side is not harmful, but doesn't seem to do much and thus would be rare.
Avoiding the extra wrapping for Threadless would be a win. We had realized that earlier, but hadn't wanted to special-case it. The wins though are nice, so it is probably worth it.
SynchronizationContext would be a rarer case, although it can show up in OobChannel for Load Balancers.
// Use reflection to maintain compatibility with Guava versions < 23.1 | ||
Class<? extends Executor> seqExecutorClass = | ||
lookupExecutorClass("com.google.common.util.concurrent.SequentialExecutor"); | ||
if (!wrapSerialized && seqExecutorClass == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drive-by nit: wrapSerialized is guaranteed to be false here
// returns null if not found or not loadable | ||
private static Class<? extends Executor> lookupExecutorClass(String name) { | ||
try { | ||
return (Class<? extends Executor>) Class.forName(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drive-by nit: Instead of the cast, use asSubclass(Executor.class)
For Netty, any Unfortunately, Netty would also need to be handled by reflection. On the plus side, it seems there would be no benefit to checking for the shaded Netty in grpc-netty-shaded. I guess the only time Netty EventLoops will be provided is for clients. I guess we could also detect EventLoopGroup and call I'm not sure I want to go down the rabbit hole optimizing for Netty event loops at this point. |
If a blocking ThreadlessExecutor is being used, or the user-provided executor is a sequential executor created via MoreExecutors.newSequentialExecutor(), it doesn't need to be wrapped in a SerializingExecutor in ClientCallImpl and ServerImpl.
Thanks @ejona86, have addressed your code comments.
Agree on server side it would be kind of unusual/niche - possibly when some kind of up-front processing has to be done in a serialized manner based strictly on arrival order.
Also agree ... it's maybe unfortunate that we can't reliably detect single-thread thread pools, for example those returned from
I don't quite follow - do you mean specifically guava's or executors with sequential properties in general? I don't think it would be that uncommon for requests to be made from "event loops" which have the required properties. These wouldn't necessarily be based on guava's sequential executor but supporting this would at least give consuming libraries/apps the option of changing to use that to avoid the additional intermediate executor overhead - my own case matches this which is what motivated this PR.
The thought was to cover known executor types which fit the requirements, even if it would be rare for them to show up.
The characteristics of
Fair enough, as implied in the original description this was more kind of wishful thinking! Impl-wise though it would be just adding another class to the list of executor types (using reflection like you say, as is done for others). |
@ejona86 Can you clarify?
|
@njhill do you still want to pursue this PR? |
If a blocking
ThreadlessExecutor
is being used, or the user-provided executor is a sequential executor created via guava'sMoreExecutors.newSequentialExecutor()
, it doesn't need to be wrapped in aSerializingExecutor
inClientCallImpl
andServerImpl
.In-process
TransportBenchmark
shows speedup of 5-10% (this is with stats/tracing disabled). Note that both thedirect
andsequential
parameters only actually affect the server-side sinceThreadlessExecutor
is used for blocking calls on client side regardless.It would be awesome if we could also include appropriate netty executor classes in the list though I guess that might be considered more "dangerous" since those generally aren't
final
.This is kind of a second swing at #3914 :)