C#8异步流与REST/RPC

C#8异步流与REST/RPC,c#,async-await,stream,c#-8.0,iasyncenumerable,C#,Async Await,Stream,C# 8.0,Iasyncenumerable,我相信这个问题会证明我的无知,但我很难理解这一点。我愿意问一个愚蠢的问题来得到一个好的答案 我读过的所有关于异步流的帖子都很好地展示了这一特性,但它们没有解释为什么它比其他方法有所改进 或者,什么时候应该在良好的旧客户机-服务器通信上使用异步流 我可以看出,流式传输大文件的内容可能是异步流的良好用途,但我看到的许多示例都使用异步流传输少量传感器数据(例如,温度)。似乎带有温度传感器的物联网设备可以将数据通过HTTP发送到服务器,服务器可以响应。在这种情况下,服务器为什么要实现异步流 我已经能感觉

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

我读过的所有关于异步流的帖子都很好地展示了这一特性,但它们没有解释为什么它比其他方法有所改进

或者,什么时候应该在良好的旧客户机-服务器通信上使用异步流

我可以看出,流式传输大文件的内容可能是异步流的良好用途,但我看到的许多示例都使用异步流传输少量传感器数据(例如,温度)。似乎带有温度传感器的物联网设备可以将数据通过HTTP发送到服务器,服务器可以响应。在这种情况下,服务器为什么要实现异步流

我已经能感觉到你在努力理解那些话时的痛苦,但请宽恕我。:)

根据要求,这里有一些我遇到的让我困惑的例子。我会在找到它们后发布更多内容,但我想继续,让您开始:

  • NET Conf主题演讲的前半部分是一个大型异步流演示。。。我不明白他们为什么在这里使用异步流:
  • 这让我很困惑

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

忘记你听说过的
异步流
。他们在想什么?

将其称为
wait foreach
,或
async enumerables
async迭代器
。它与IO和streams无关

之所以使用这个术语,是因为它存在于其他语言中,而不是因为它与IO有任何关系。例如,在Java中,流是C#的IEnumerable的Java实现。因此,为了便于未来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;
    }
}
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
}
在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中,响应可以在到达时接收和处理:

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;
    }
}
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
}

**

这两者根本不相关。异步流是一个与网络无关的编程概念。不过,这种编程概念可用于使gRPC流更易于编写。你可以参考你所看到的一些帖子,告诉我们你对它们的理解,然后我们可以尝试找出任何混淆点。这些都是互补的概念,而不是相互竞争的概念。在特征上;请注意,异步流的实现本身如何使用“良好的旧客户机-服务器通信”,就像它使用标准的HTTP POST一样。我已经更新了这个问题,以包括我最近遇到的一些帖子。我会努力找到更多。。。但是,我想真正的问题可能是,“异步流何时合适”?@chill94给出的例子很有帮助,我认为。。。异步流是“基于拉”的,并且允许中间结果和取消,这是驱动因素吗?显然,我仍在努力组织头脑中的想法,并阐述问题。当我开始写这篇文章时,我真的不知道该问什么,所以这些评论对我很有帮助。谢谢。@AlexDresko不,这两件事没有关系。异步流是
等待foreach
和IAsyncEnumerable。与IO、HTTP和网络无关。它们可以用来使调用gRPC流变得更容易,我会说,(也许这是一种语言,比其他任何东西都重要)将它们称为“无关”可能有点强。我想说“++”操作符和“for”循环是相关的,因为我经常在相同的上下文中看到它们。这里也一样。我这样说并不是为了批评你——你的回答很贴切——但它可能有助于向未来的读者阐明你的观点。这些概念是相关的,因为它们通常在同一上下文中出现。
HttpClient.GetStringAsync
返回一个
任务
,因此该示例似乎不正确。天气的例子正是令人困惑的地方。天气数据流永远不会结束,因为天气永远不会结束。没有“在收到所有响应之前阻止”这样的事情,因为结束永远不会到来。在C#8之前,客户端可能会轮询服务器,或者服务器会将天气数据推送到客户端。因此,我认为异步流适用于“基于拉”的情况。我错了吗?@AlexDresko
等待httpClient.GetStringAsync($“{baseUrl}/{I}”)
生成一个字符串。至于天气的例子,它是关于这个particualr示例代码的,它只返回几十个带有人为延迟的响应。调用结束了。@AlexDresko忘了你听说过的
异步流
,想想
等待foreach
。我必须自己努力调用此功能
异步流
。之所以使用这个术语,是因为它存在于其他语言中,而不是因为它与IO有任何关系。例如,在Java中,当.NET的IEnumerable是基于拉的时,流是基于推的迭代器。现在忘了推还是拉,因为这和gRPC@AlexDresko你在说什么代码<代码>等待客户端。GetStringAsync()返回单个值。是yield-return立即在迭代器中返回该值。至于
i
,这是URL的一部分。我试图说明概念之间的区别,并说明它们之间没有任何区别