-2

In my project's code base, I see a lot of methods that boil down to the following code:

public async Task<bool> MyAsyncFunction(string filePath) 
{
   byte[] fileBytes = await File.ReadAllBytesAsync(filePath);
   bool succeeded = await UploadFileSomewhereAsync(fileBytes);

   return succeeded;
}

I understand that async/await is useful for non-blocking UI tasks in front-end code. I also understand that async/await can be used to run certain tasks in parallel, as in the code below:

public async Task<bool> MyAsyncFunction(string filePath) 
{
   Task<byte[]> fileBytesTask = File.ReadAllBytesAsync(filePath);

   // do some other work that does not need the file byte array

   byte[] fileBytes = await fileBytesTask;
   bool succeeded = await UploadFileSomewhereAsync(fileBytes);

   return succeeded;
}

However, how is the async/await pattern of any use in the first example? Is there any benefit of writing code like this over simply calling the synchronous versions of these methods? Am I missing something?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Alma
  • 3
  • 1
  • 9
    But.. you just wrote *I understand that async/await is useful for non-blocking UI tasks in front-end code* - how can reading a 2 gigabyte file into memory and then slowly uploading it to some place, all the while not having an app looking like it's crashed *not* seem like a good idea? – Caius Jard Sep 14 '21 at 12:58
  • 1
    As simple as it gets. The alternative to async/await is basically a worker thread (with possibly some not too easy interactions with the UI) - or your app looks like it crashed and you can not even move a window because the UI thread is stuck. – TomTom Sep 14 '21 at 13:01
  • 2
    The end goal of `async`/`await` is to free up threads. For UI apps, freeing up the GUI thread makes the app more responsive. For server apps, freeing up threads makes the app more scalable. – Stephen Cleary Sep 14 '21 at 13:01
  • although it appears as though `await File.ReadAllBytesAsync(filePath)` is run synchronously, it isn't. The file read is likely (but not necessarily) run on a another thread leaving a UI thread free to do what is needed while the file is being read. Once the operation finishes, control is returned to the original thread. – phuzi Sep 14 '21 at 13:01
  • @CaiusJard Of course I do not want my front-end to look like it crashed, so I will create a front-end implementation that is something like – Alma Sep 14 '21 at 13:34
  • OK, so think of it in more general terms then; Employees. If you have a product that takes 10 steps to make, and you only need to make one. Let's say you hire 10 people who each know how to do one step. and you set them going on making it. At any point 1 of them is working and 9 are sitting around drinking coffee and waiting their turn to do something. Now let's change things up, tell those 9 instead of sitting around doing nothing, go find something else to do; sweep the floor, make some sales calls, restock the toilet paper.. Maybe you can get by with fewer employees overall , not just the.. – Caius Jard Sep 14 '21 at 13:34
  • ..makers, but save on admin and cleaners etc because in their spare time the makers are cleaning, calling. Async/await isn't necessarily multithreading in the sense of X people making X products simultaneously, "and that's all they know how to do/if they get blocked they stop", it's more like "making better use of spare time with more limited resources, by arranging for blocked resources to go and do something else until the block is released". Your FE might not be blocked, but your precious server resources being tied up sitting around waiting for IO is a big waste of server time.. – Caius Jard Sep 14 '21 at 13:37
  • The funny thing in your question is that the async example that you've chosen, the `File.ReadAllBytesAsync` method, is currently (.NET 5) [poorly implemented](https://stackoverflow.com/questions/63217657/why-file-readalllinesasync-blocks-the-ui-thread). Not only it blocks the calling thread, but also it blocks it for far longer than the synchronous `File.ReadAllBytes` method. AFAIK things are going to [get better](https://devblogs.microsoft.com/dotnet/announcing-net-6-preview-4/#significantly-improved-filestream-performance-on-windows) with the advent of .NET 6. – Theodor Zoulias Sep 14 '21 at 15:50
  • @CaiusJard when an answer does not fit in one comment, that's probably an indication that you should post it as an answer. [Some would say](https://prnt.sc/1s6jo2s) that even if it fits in one comment, answering questions in comments should be avoided anyway. – Theodor Zoulias Sep 14 '21 at 15:54
  • Lol.. I'm sure you meant to say "when a comment doesn't fit in one comment" - a good law abiding citizen such as myself would never dream to post an answer in a comment :) – Caius Jard Sep 14 '21 at 16:49

1 Answers1

0

To expand a bit on Stephen Clearys comment

There are two main use cases for asynchronous code.

  1. For UI applications you do not want to freeze your UI while doing some slow IO-operation, like reading a large file, or doing something process intensive.
  2. For server applications you do not want to consume a thread while waiting for slow IO operations. Many servers are fairly simple front ends for a database. If you have 1000 concurrent queries and are using synchronous code, you might require 1000 threads that are just waiting. Threads uses some resources, like memory, and this becomes wasteful when trying to service a large number of concurrent users.

The older styles of doing writing asynchronous code was a bit difficult to use, since you need to manually keep track of everything that is needed to be done after the IO operation completed. Async/awaits largely avoids this by making the compiler do the difficult parts, letting you write code that looks like regular sequential code.

A criticism against async/await is that sometimes it is better to use synchronous methods. So you might be required to write two versions of essentially the same code.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • Thank you for your answer, the ‘server as a front end for the db’ is a useful analogy! – Alma Sep 14 '21 at 16:33