Asynchronous memory streaming approach: which of the following?

10,363

The fact is that MemoryStream's Read/WriteAsync methods don't actually provide any kind of true asynchronous implementation. All they do is perform the operation synchronously and return an already completed Task. Therefore there is no benefit to calling the async methods when you know it's a MemoryStream. In fact, it's just completely unnecessary overhead.

Now, forgetting that for a second just to answer your question on style, the first approach is better one because you don't allocate/schedule a new Task unnecessarily (e.g. with Task::Run), but I don't know why you wouldn't just use a using() statement in that approach. So here's the cleanest/simplest IMHO:

private async static Task WriteToStreamFirstVariantSimplified()
{
    using(MemoryStream memoryStream = new MemoryStream())
    {
        byte[] data = new byte[256];

        try
        {
            await memoryStream.WriteAsync(data, 0, data.Length);
        }
        catch(Exception exception)
        {
            //Handling exception
        }
   }
}
Share:
10,363
Ilya Tereschuk
Author by

Ilya Tereschuk

Updated on June 08, 2022

Comments

  • Ilya Tereschuk
    Ilya Tereschuk almost 2 years

    I am working on solution which uses asynchronous memory streaming and I am thinking about right approach for implementing such. Which one is more convenient? The first, simple:

    //First approach: linear async
    private async static Task WriteToStreamFirstVariant()
    {
        MemoryStream memoryStream = new MemoryStream();
        byte[] data = new byte[256];
        try
        {
            await memoryStream.WriteAsync(data, 0, data.Length);
        }
        catch(Exception exception)
        {
            //Handling exception
        }
        finally
        {
            memoryStream.Dispose();
        }
    }
    

    Or the second with nested tasks and closures?

    //Second approach: nested tasks async
    private async static Task WriteToStreamSecondVariant()
    {
        await Task.Run(async () =>
        {
            byte[] data = new byte[256];
            using (MemoryStream memoryStream = new MemoryStream())
            {
                await memoryStream.WriteAsync(data, 0, data.Length)
                    .ContinueWith((Task writingTask) =>
                    {
                        //Handling exceptions
                        AggregateException exceptions = writingTask.Exception;
                    });
            }
        }); 
    }
    
  • usr
    usr over 10 years
    Just don't use async here. The code snippet in this answer shows a bad practice. I worry that someone might copy it and use it.
  • Drew Marsh
    Drew Marsh over 10 years
    I totally agree, but people should hopefully be reading the explanation first. In the end, I just wanted to provide the best way to write the code from an async perspective, but you absolutely shouldn't waste your cycles (or the CPU's) writing it this way for MemoryStream.
  • David L. Sargent
    David L. Sargent almost 8 years
    Also note that MicroSofts version of MemoryStream.CoptyToAsync is there for a reason. If you are trying to to MemoryStream.CopyTo in an Async method it will fail under heavy load sometimes. Switching to CopyToAsync fixed this for us.
  • FreakyAli
    FreakyAli over 4 years
    @DavidL.Sargent Been trying to use the CopyToAsync method for so long now it never works!! the resulting stream is always empty