我想写一个专业的回复,但可能也需要粗略的回复:
忘记你听说过async streams
。他们在想什么?
叫它await foreach
,或async enumerables
或async 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;
}
}
当它们显示为操作结果时,仅允许 ASP.NET Core 中间件在生成结果时开始处理结果,它们不会影响 HTTP 响应本身的内容。
另一方面, gRPC 的流允许服务器异步向客户端发送单独的响应。gRPC 和 C# 8 异步流中的 Laurent Kempe和使用 GRPC 和 .NET Core的服务器流中的 Steve Gordon展示了如何将它们一起使用
复制 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);
}
在 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
}
但是在 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
}
**