为什么我的Node.js gRPC客户端需要3秒钟才能向我的Python gRPC服务器发送请求



让我们首先承认我是一个gRPC noob。如果我问了一个愚蠢的问题,请继续告诉我,但只有在解释为什么它很愚蠢之后。谢谢!:(

概述

我正在开发一个处理图像的应用程序。影响处理结果的变量可由用户更改。我想在保持跨平台兼容性的同时提供一个好看的GUI。因此,我决定用Python实现我的图像处理,并使用Node.js和Electron作为我的GUI。

由于需要一种向Python后端发送数据和从Python后端接收数据的方法,我决定使用gRPC。因此,我有一个Node.js gRPC客户端Python gRPC服务器配对。

在阅读了许多教程并学习了一些关于协议缓冲区的知识后,我能够成功地在两个程序之间传输数据。

设置

Node.js Electron应用程序接受用户的输入,并向Python后端发送请求。请求的大小是一个小对象:

// From My Protocol Buffer
message DetectionSettings {
float lowerThreshold = 1;
float upperThreshold = 2;
float smallestObject = 3;
float largestObject  = 4;
float blurAmount     = 5;
int64 frameNumber    = 6;
string streamSource  = 7;
}

收到此请求后,Python应用程序从指定的streamSource中读取一个帧并对其进行处理。然后将处理后的帧转换为JPEG格式,并通过gRPC作为Image:返回到Node.js应用程序

// From My Protocol Buffer
message Image {
bytes image_data = 1;
int32 height = 2;
int32 width = 3;
int64 frame = 4;    
}

问题

我注意到,在发出请求和接收图像之间存在可变的延迟。此时间从几毫秒到近3秒不等!在分析完Python代码之后,我确定处理时间可以忽略不计。此外,通过gRPC返回Image所花费的时间也可以忽略不计。

因此,在RPC执行和Python应用程序接收调用之间存在一个有趣的延迟。以下是一些带有时间的日志,可以更好地解释发生了什么(括号中的数字以秒为单位(:

/* Node.js */
[160408.072] "Sending Request..."
[160408.072] "Executing RPC"
[160408.072] "RPC Executed"
/* Python */
[160411.032] [ py-backend ] Getting frame
/* Node.js */
[160411.617] "Got Data"

您可以看到,在这种情况下,从Node.js RPC执行到调用Python方法的时间大约为3秒,而从执行Python方法到Node.js应用程序接收Image的时间不到1秒0.o

守则

Python gRPC服务器

# Create the server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
# Add our service to the server
processor_pb2_grpc.add_ProcessorServicer_to_server(
ProcessorServicer(), server
)
server.add_insecure_port('[::1]:50053')
server.start()
server.wait_for_termination()

Node.js客户端:

const grpc = require('grpc')
const PROTO_PATH = '../processor.proto'
const serviceConfig = {
"loadBalancingConfig": [ {"round_robin": {} } ]
}
const options = {
'grpc.service_config': JSON.stringify(serviceConfig)
}
const ProcessorService = grpc.load(PROTO_PATH).Processor
const client = new ProcessorService ('[::1]:50053',
grpc.credentials.createInsecure(), options);
module.exports = client

协议缓冲区:

syntax = "proto3";
message Number {
float value = 1;
}
message Image {
bytes image_data = 1;
int32 height = 2;
int32 width = 3;
int64 frame = 4;    
}
message DetectionSettings {
float lowerThreshold = 1;
float upperThreshold = 2;
float smallestObject = 3;
float largestObject  = 4;
float blurAmount     = 5;
int64 frameNumber    = 6;
string streamSource  = 7;
}
service Processor{
rpc GetFrame(DetectionSettings) returns (Image) {};
}

Node.js gRPC调用:

function GetFrameBytes(detectionSettings, streamSource, frameNumber, callback)
{
detectionSettings["streamSource"] = streamSource;
detectionSettings["frameNumber"] = frameNumber;
client.GetFrame(detectionSettings, (error, response) =>
{
if(!error){
callback(response)
}
else
{
console.error(error);
}
});
}

tl;dr

为什么我的Node.js客户端请求触发我的Python代码要花这么长时间?

有几个因素可能会影响您看到的长时间。

首先,客户端发出的第一个请求总是需要更长的时间,因为它必须进行一些连接设置工作。一般的预期是,一个客户端将发出许多请求,并且设置时间将分摊到所有这些请求中。

第二,你提到你正在使用Electron。有一些报告称,当在Electron渲染过程中使用时,节点的gRPC表现不佳。在主进程或常规Node进程中运行代码时,可能会看到不同的结果。

如果您尝试包@grpc/grpc-js,您可能也会有不同的运气,它是Node gRPC库的完全重新实现。当前用于加载.proto包的API不在该库中,但使用@grpc/proto-loader的替代方法可用于两种实现,其他API相同。

最新更新