C# 8 异步流与 REST/RPC

Ale*_*sko 4 c# stream async-await c#-8.0 iasyncenumerable

我确信这个问题会证明我的无知,但我很难理解这一点。我愿意问一个愚蠢的问题以获得一个好的答案。

我读过的所有关于异步流的帖子都很好地展示了该功能,但它们没有解释为什么它比替代方案有所改进。

或者,也许,什么时候应该通过良好的旧客户端 - 服务器通信使用异步流?

我可以看到流式传输大文件的内容对于异步流来说可能是一个很好的用途,但是我看到的许多示例都使用异步流来传输少量传感器数据(例如温度)。似乎带有温度传感器的 IoT 设备只需通过 HTTP POST 将数据发送到服务器,服务器就可以响应。在这种情况下,服务器为什么要实现异步流?

当你努力理解这些话时,我已经能感受到你的痛苦,但请怜悯我。:)

根据要求,这里有一些我遇到的让我感到困惑的例子。当我找到它们时,我会发布更多,但我想继续让你开始:

Pan*_*vos 7

我想写一个专业的回应,但可能也需要粗略的回应:

忘记你曾经听说过async streams。他们在想什么?

调用它await foreach, 或async enumerablesasync iterators。它与 IO 和流无关。

使用该术语是因为它存在于其他语言中,而不是因为它与 IO 有任何关系。例如,在 Java 中,流是 Java 对 C# IEnumerable 的实现。因此,为了便于未来的 Android 开发人员采用,C# 采用了 Java 的坏主意。

我想我们可以查看语言设计会议以了解这个术语的实际理由。


认真的原答案

没有vs。这就像对比自动变速箱和汽车。汽车可以自动变速箱,它们不是用来代替变速箱的。

异步流纯粹是一个允许创建异步迭代的编程概念。该功能允许我们编写此功能以在循环中进行 HTTP 调用并在结果到达时对其进行处理:

await foreach(var someValue from someAsyncIterator(5))
{
    ...
}

IAsyncEnumerable<string> someAsyncIterator(int max)
{
    for(int i=0;i<max;i++)
    {
        var response=await httpClient.GetStringAsync($"{baseUrl}/{i}");
        yield return response;
    }
}
Run Code Online (Sandbox Code Playgroud)

当它们作为操作结果出现时,它只允许 ASP.NET Core 中间件在产生结果时开始处理结果,它们不会影响 HTTP 响应本身的内容。

另一方面,gRPC 的流允许服务器异步向客户端发送单独的响应。Laurent Kempe in gRPC and C# 8 Async stream和 Steve Gordon in Server Streaming with GRPC and .NET Core展示了如何一起使用这些

从 Steve Gordon 的样本中复制,假设我们有一个向客户端发送预报的天气服务,其 proto 文件包含:

service WeatherForecasts {
  rpc GetWeather (google.protobuf.Empty) returns (WeatherReply);
  rpc GetWeatherStream (google.protobuf.Empty) returns (stream WeatherData);
  rpc GetTownWeatherStream (stream TownWeatherRequest) returns (stream TownWeatherForecast);
}
Run Code Online (Sandbox Code Playgroud)

在 C# 8 之前,客户端在处理它们之前必须阻塞,直到它收到所有响应:

using var channel = GrpcChannel.ForAddress("https://localhost:5005");
var client = new WeatherForecastsClient(channel);
var reply = await client.GetWeatherAsync(new Empty());
foreach (var forecast in reply.WeatherData)
{
        //Do something with the data
}
Run Code Online (Sandbox Code Playgroud)

但是,在 C# 8 中,可以在响应到达时接收和处理响应:

using var replies = client.GetWeatherStream(new Empty(), cancellationToken: cts.Token);

await foreach (var weatherData in replies.ResponseStream.ReadAllAsync(cancellationToken: cts.Token))
{
        //Do something with the data
}
Run Code Online (Sandbox Code Playgroud)

**

  • @AlexDresko 只是忘记您曾经听说过“异步流”并考虑“await foreach”。我自己必须努力将此功能称为“异步流”。使用该术语是因为它存在于其他语言中,而不是因为它与 IO 有任何关系。例如,在 Java 中,流是基于推的迭代器,而 .NET 的 IEnumerable 是基于拉的。现在忘记推-与拉-因为它与 gRPC 无关 (2认同)