Как заметил @Mike, GrpcChannel использует HttpClient под капотом. Итак, согласно this , мы, вероятно, можем создать одного 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];
Stopwatch watcher = new Stopwatch();
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!");
});
}
watcher.Start();
for (int i = 0; i < threadCount; ++i)
{
threads[i].Start(i);
}
for (int i = 0; i < threadCount; ++i)
{
threads[i].Join();
}
watcher.Stop();
Console.WriteLine($"Elapsed time: {watcher.ElapsedMilliseconds}");
Собственный канал для каждого потока
string uri = $"https://localhost:5001";
int threadCount = 6;
Thread[] threads = new Thread[threadCount];
Stopwatch watcher = new Stopwatch();
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);
watcher.Start();
for (int i = 0; i < threadCount; ++i)
{
threads[i].Start(i);
}
for (int i = 0; i < threadCount; ++i)
{
threads[i].Join();
}
watcher.Stop();
Console.WriteLine($"Elapsed time: {watcher.ElapsedMilliseconds}");
Я получаю примерно одинаковое время в обоихслучаи без каких-либо ошибок.
Резюме, я могу сделать вывод, что мы можем создать один канал GRPC и повторно использовать его в приложении.