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);
}
}
source to share
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 .
source to share