Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# 8 Async Streams vs REST/RPC

I'm sure this question is going to prove my ignorance, but I'm having a hard time understanding this. I'm willing to ask a dumb question to get a good answer.

All of the posts I've read about async streams do a good job of showing off the feature, but they don't explain why it's an improvement over the alternative.

Or, perhaps, when should one use async streams over good old client-server communication?

I can see where streaming the contents of a large file might be a good use for async streams, but many of the examples I've seen use async streams to transmit small bits of sensor data (temperature, for example). It seems like an IoT device with a temperature sensor could just HTTP POST the data to a server, and the server could respond. Why would the server implement async streams in that case?

I can already feel your pain as you struggle to make sense of those words, but please have mercy on me. :)

As requested, here are some examples I've come across that confused me. I'll post more as I find them, but I wanted to go ahead and get you started:

  • The first half of the .NET Conf keynote was a massive async stream demo... I couldn't understand why they were using async streams here: https://www.youtube.com/watch?v=1xQE2bWkwjo&list=PLReL099Y5nRd04p81Q7p5TtyjCrj9tz1t&index=4&t=
  • Here's another example that confused me
like image 574
Alex Dresko Avatar asked Oct 16 '19 12:10

Alex Dresko


1 Answers

I wanted to write a professional response but the crude one is probably needed too:

Forget you ever heard about async streams. What were they thinking?

Call it await foreach, or async enumerables or async iterators. It has nothing to do with IO and streams.

The term is used because it exists in other languages, not because it has anything to do with IO. In Java for example, streams are Java's implementation of C#'s IEnumerable. So, to ease adoption by future Android devs, C# adopted Java's bad idea.

We can look at the language design meetings for the actual justification for this term I guess.


Serious original answer

There's no vs. It's like contrasting automatic gear boxes and cars. Cars can have automatic gear boxes, they aren't used instead of gear boxes.

Async streams is purely a programming concept that allows the creation of async iteratos. It's the feature that allows us to write this to make HTTP calls in a loop and process the results as they arrive :

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

When they appear as action results it's only to allow the ASP.NET Core middleware to start processing results as they are produced, they don't affect the contents of the HTTP response itself.

gRPC's streams on the other hand allow the server to send individual responses to the client asynchronously. Laurent Kempe in gRPC and C# 8 Async stream and Steve Gordon in Server Streaming with GRPC and .NET Core show how these can be used together

Copying from Steve Gordon's samples, let's say we have a weather service that sends forecasts to the client, whose proto file contains :

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

Before C# 8, the client would have to block until it received all responses before processing them:

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
}

In C# 8 though, the responses can be received and processed as they arrive :

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
}

**

like image 113
Panagiotis Kanavos Avatar answered Oct 24 '22 23:10

Panagiotis Kanavos