【问题标题】:Creating gRPC server with c#. Return types Task?使用 c# 创建 gRPC 服务器。返回类型任务?
【发布时间】:2021-12-17 15:56:43
【问题描述】:

我用 C# 创建了一个 gRPC 服务器。非常简单。 让我困惑的是,所有消息请求的返回类型都是Tasks

来自问候服务器示例:

public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
    return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}

我想知道为什么返回类型不只是HelloReply。我开始创建自己的服务器并继续返回Task.FromResult,但实际上这不是 Task 的使用方式。所以我担心我错过了一些东西(关于性能?)。但另一方面,我无法想象可能有什么问题。对于每个请求,gRPC 服务器本身都是并行的,不是吗? 那么我在什么情况下返回Task有用呢?

【问题讨论】:

    标签: c# grpc


    【解决方案1】:

    并发(并行)不同于异步(任务等);使用阻塞(非异步)调用意味着在您的操作期间有一个线程专门用于您的操作,考虑到大多数真实服务都涉及外部 IO(数据库,文件等)- here 异步增加了巨大的好处。线程昂贵且有限 - 这会人为地限制吞吐量,这可以通过异步来避免。返回诸如Task&lt;HelloReply&gt;ValueTask&lt;HelloReply&gt; 之类的可等待内容是允许(但不要求)事物异步的先决条件。

    如果你不需要它(这似乎不太可能):使用Task.FromResult,就像你正在做的那样。或者,如果您使用的是 protobuf-net.Grpc:直接支持同步方法(它基本上与您的操作方式非常相似)。

    【讨论】:

    • 那么用于从数据库异步获取数据的任务比处理 rpc 请求的任务占用的空间更小?
    • @Klamsi 在这种情况下,任务不会“处理”任何事情 - 它们是现在可能已知或将来可能已知的结果的占位符- 仅此而已;实际意义上的足迹并不大,如果可能的话:ValueTask[&lt;T&gt;] 甚至可以帮助减少这一点。通过 ADO.NET 从数据库中获取数据通常有很多相关的包袱(众所周知,ADO.NET API 涉及很多对象),因此:与正在发生的所有其他事情相比:a @ 987654325@ 结果基本没什么。在某些情况下(不是这个),任务开销可能很重要,并且可以通过技巧进行优化。
    • 我想我明白了,谢谢。所以肯定存在并行性,但是对于 Task.FromResult 一个线程在请求​​期间被阻塞,而对于异步它可以同时被重用。总而言之:它可以节省内存。
    • @Klamsi 不是内存 - 线程(如果有的话,它会花费 很小 的内存量来允许你这样做)
    • @Klamsi 不是真的,不 - 虽然线程确实每个线程都有内存成本(对于堆栈空间),所以从某个角度来看您可能会争辩说,由于使用异步允许您使用更少的线程处理相同的负载,您将节省大量与其堆栈开销相关的内存。事实上,线程的内存成本是为什么你不只是为每个单独的请求生成一个新线程,让它做任何事情,然后死掉。
    猜你喜欢
    • 2021-11-18
    • 2019-09-14
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多