How to work with a synchronous method / task using async / await

I am trying to figure out how to use asnet / await.net 4.5 keywords with a job that is synchronous on it. That is, some kind of complex mathematical calculation. I used Thread.Sleep to simulate this action in the example below. My question is, how can you make a method like this act like an async method? If not, you just have to do what I did in the ThisWillRunAsyncTest method and do something like Task.Factory.StartNew on this sync method. Is there a cleaner way to do this?

using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;

using NUnit.Framework;

[TestFixture]
public class AsyncAwaitTest
{
    [Test]
    //This test will take 1 second to run because it runs asynchronously
    //Is there a better way to start up a synchronous task and have it run in parallel.
    public async void ThisWillRunAsyncTest()
    {
        var tasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            tasks.Add(Task.Factory.StartNew(() => this.RunTask()));
        }

        await Task.WhenAll(tasks);
    }

    [Test]
    //This test will take 5 seconds to run because it runs synchronously.
    //If the Run Task had an await in it, this this would run synchronously.  
    public async void ThisWillRunSyncTest()
    {
        var tasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            tasks.Add(this.RunTask());
        }

        await Task.WhenAll(tasks);
    }

    //This is just an example of some synchronous task that I want to run in parallel.
    //Is there something I can do in this method that makes the async keyword work?  I.e. this would run asynchronously when called from ThisWillRunSyncTest
    public async Task RunTask()
    {
        Thread.Sleep(1000);
    }
}

      

+3


source to share


1 answer


Generally, if you are doing parallel work, you should use Parallel

LINQ or parallel.

There are times when it is convenient to treat processor-related work as if it were asynchronous (that is, doing it on a background thread). It is used for this Task.Run

(avoid using StartNew

as I described in my blog ).

Synchronous methods must have synchronous method signatures:

public void RunTask()
{
  Thread.Sleep(1000);
}

      

They should only be wrapped in Task.Run

if calling code requires it (i.e. it is part of a UI component such as a view model):



var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
  tasks.Add(Task.Run(() => this.RunTask()));
}
await Task.WhenAll(tasks);

      

The principle here is what Task.Run

should be used in the call, not in the implementation; I'll go into detail on my blog .

Note that if you have real complexity, you should use Parallel

either parallel LINQ instead of a set of tasks Task.Run

. Task.Run

great for little things, but it doesn't have all the skills that parallel types do. So, if it's part of a library (and doesn't necessarily work on the UI thread), I would recommend using Parallel

:

Parallel.For(0, 5, _ => this.RunTask());

      

As a final side note, asynchronous unit test methods should be async Task

, not async void

. NUnit v3 has already removed support for async void

unit test methods .

+11


source







All Articles