[英]An using GRPC Channel concurrently in Net Core 3.0
根据文档,gRPC 客户端是从通道创建的。 可以从一个通道创建多个具体的 gRPC 客户端,包括不同类型的客户端,但我没有找到任何有关并发的信息。
所以,我的问题是,我可以使用该通道进行如下并发呼叫吗?
var channel = GrpcChannel.ForAddress("https://localhost:5001");
// the first task
Task.Run(() => {
var client = new Greet.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });
Console.WriteLine("Greeting: " + response.Message);
});
// the second task
Task.Run(() => {
var client = new Greet.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });
Console.WriteLine("Greeting: " + response.Message);
});
或者我需要为每个线程(任务)创建自己的通道。
正如@Mike 所指出的,GrpcChannel 在后台使用 HttpClient。 因此,根据这个,我们可能可以创建单个 http 客户端并在应用程序的整个生命周期中重用它。
HttpClient 旨在被实例化一次并在应用程序的整个生命周期中重复使用。
我已经建立了一个简单的示例来调查该区域。
GRPS服务:
public class GreeterService
: Greeter.GreeterBase
{
private readonly ILogger<GreeterService> _logger;
public GreeterService(ILogger<GreeterService> logger)
{
_logger = logger;
}
//Server side handler of the SayHello RPC
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
_logger.LogInformation($"Sending hello to {request.Name}");
Thread.Sleep(500);
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
}
所有线程的单一通道
string uri = $"https://localhost:5001";
var channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions()
{
HttpClient = HttpClientFactory.Create(),
DisposeHttpClient = true
});
int threadCount = 6;
Thread[] threads = new Thread[threadCount];
for(int i = 0; i < threadCount; ++i)
{
threads[i] = new Thread((index) =>
{
Console.WriteLine($"Thread({(int)index}) has been started!");
for (int req = 0; req < 75; ++req)
{
var client = new Greeter.GreeterClient(channel);
client.SayHello(new HelloRequest()
{
Name = $"Thread {(int)index}"
});
}
Console.WriteLine($"Thread({(int)index}) has been finished!");
});
}
for (int i = 0; i < threadCount; ++i)
{
threads[i].Start(i);
}
for (int i = 0; i < threadCount; ++i)
{
threads[i].Join();
}
每个线程都有自己的频道
string uri = $"https://localhost:5001";
int threadCount = 6;
Thread[] threads = new Thread[threadCount];
for(int i = 0; i < threadCount; ++i)
{
threads[i] = new Thread((index) =>
{
var channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions()
{
HttpClient = HttpClientFactory.Create(),
DisposeHttpClient = true
});
Console.WriteLine($"Thread({(int)index}) has been started!");
for (int req = 0; req < 75; ++req)
{
var client = new Greeter.GreeterClient(channel);
client.SayHello(new HelloRequest()
{
Name = $"Thread {(int)index}"
});
}
Console.WriteLine($"Thread({(int)index}) has been finished!");
});
}
Thread.Sleep(1000 * 10);
for (int i = 0; i < threadCount; ++i)
{
threads[i].Start(i);
}
for (int i = 0; i < threadCount; ++i)
{
threads[i].Join();
}
总结,我可以得出一个结论,我们可以创建一个单一的 GRPC 通道并在应用程序中重用它。 但我不知道使用一个渠道处理多个请求的效果如何
我看到这个问题得到了回答,但我想补充一点,文档中有关于客户端并发的部分。 如果有人新阅读了这个问题,我希望这会有所帮助。
关于gRPC 性能和实践的“重用 gRPC 通道”一章。
通道可以安全地在 gRPC 调用之间共享和重用:
- gRPC 客户端是使用通道创建的。 gRPC 客户端是轻量级对象,不需要缓存或重用。
- 可以从一个通道创建多个 gRPC 客户端,包括不同类型的客户端。
- 一个通道和从通道创建的客户端可以被多个线程安全地使用。
- 从通道创建的客户端可以同时进行多个调用。
“连接并发”一章对这个主题也很有帮助。
注意:查看主题配置以配置服务和客户端通道。
GrpcChannel
表示一个 gRPC 通道。 通道是与远程服务器的长期连接的抽象。 客户端对象可以重用相同的通道。 与调用远程调用相比,创建通道是一项昂贵的操作,因此通常您应该为尽可能多的调用重用单个通道。
没有关于客户端并发的细节,但核心概念主题也非常有帮助,让我们了解 gRPC 在底层是如何工作的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.