Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing an asynchronous process that can be awaited

I have been researching how to convert my (synchronous) algorithms into asynchronous ones. (TAP) First, just to be clear, this question is not about "what is Async and Await does" ( I already have read the excellent posts of Stephen Cleary , for example Async and Await (If anyone is interested read the link- it is very informative)

I have also read already the chapter on concurrency of "C# in a nutshell".

This question is not about how async functions use await to call functions either. I already know that.

Unfortunately in almost all the things I read, the await Task.Delay(10) is used to "make a asynchronous function". For example:

public async Task<int> GetResult()
{
   int result= await GiveMeTheInt();

}
public async Task<int> GiveMeTheInt() //<--is async needed here? (oops! I just realize it is...
{
  await Task.Delay(100);
  return(10);
}

In this example for instance I already understand the magic of async await in the GetResult() function but the implementation of GiveMeTheInt() is not very useful.(They just put a Delay as a generic asynchronous function and leave it at that)

So my question is about the "GiveMeTheInt"-type of questions (not the ones who call them).

The question

If I have an algorithm written in a function that so far has been synchronous, how can I convert this to be used asynchronously?


This is not a duplicate question, the closest I have found is Turning a Syncronous method async in which the poster is told to use a async version of his method that already exists. In my case, this does not exist.

My algorithms consist mainly of Image processing so in essence scanning a large array and changing the values of each pixel. Something like

void DoSomethingToImage(int[,] Image)
{
  for(int i=0;i<width;i++)
    for(int j=0;j<height;j++)
     {
       Image[i,j]=255;
     }
}

(This is a fictional example, the operation is different of course)

The closest I have gotten an answer to this is to put the function inside a Task.Run() but I am not sure if this is the way to do it.

Any help will be greatly appreciated

like image 728
KansaiRobot Avatar asked Oct 10 '17 09:10

KansaiRobot


People also ask

Can async void be awaited?

For methods other than event handlers that don't return a value, you should return a Task instead, because an async method that returns void can't be awaited. Any caller of such a method must continue to completion without waiting for the called async method to finish.

What is an asynchronous process?

An asynchronous process is a process or function that executes a task "in the background" without the user having to wait for the task to finish.

How do you wait for an async function to finish?

Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.

What happens when async method is not awaited?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.


1 Answers

So take a look at your method:

void DoSomethingToImage(int[,] image)
{
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            image[i, j] = 255;
        }
    }
}

Is this asynchronous? Obviously not. This is just CPU-bound work that will keep the processor busy for a bit. As such, it is not a good candiate to make asynchronous on its own. It should be run synchronously.

What if you are consuming this from an asynchronous part of the application? You certainly don’t want the user interface to block because you are iterating through a lot of pixels. So the solution is to load the work off to another thread. You do that using Task.Run:

await Task.Run(() => DoSomethingToImage(image));

So you would write that whenever you call the DoSomethingToImage method from an asynchronous method. Now, if you only use that method inside asynchronous contexts, you could argue that it might make sense to move the Task.Run into the function:

Task DoSomethingToImageAsync(int[,] image)
{
    return Task.Run(() => { … });
}

Is this a good idea? In general no, because now you are making the method look asynchronous when it’s in fact not. All it does is spawn a new thread that does the work, and then it waits for the thread to complete. So now you are hiding that part and also make a method doing highly synchronous work decide that a thread should be started. That’s rarely a good idea. And there is nothing wrong with keeping the method as it is, to show that it’s synchronous, and make the calling code responsible of deciding how that code should be run.

If I have an algorithm written in a function that so far has been synchronous, how can I convert this to be used asynchronously?

So, coming back to your actual question, this is actually difficult to answer. The answer is probably just this: “It depends”.

If a method does CPU-bound work, you’re better off keeping it synchronous and let calling code decide how to run it. If you are doing mostly I/O work where you interact with other interfaces (network, file system, etc.), then that’s a good candidate for making it asynchronous, especially considering that many of those interfaces will already offer asynchronous ways to communicate with them.


One final note regarding your “is async needed here?” question in your code: You need the async keyword whenever you want to use await inside of it. The mere presence of the async keyword does not make a method asynchronous though (not even the return type does indicate that).

like image 119
poke Avatar answered Sep 23 '22 02:09

poke