Как работать с синхронным методом / задачей с помощью async / wait

Я пытаюсь понять, как использовать ключевые слова asnet / await .net 4.5 с заданием, которое в его ядре является синхронным. Т.е. какой-то сложный математический расчет. Я использовал Thread.Sleep для имитации этого действия в приведенном ниже примере. Мой вопрос заключается в том, как вы можете заставить такой метод действовать как метод async? Если нет, вам просто нужно сделать то, что я сделал в методе ThisWillRunAsyncTest, и сделать что-то вроде Task.Factory.StartNew по этому методу синхронизации. Есть ли более чистый способ сделать это?

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(); for (int i = 0; i  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(); 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? Ie this would run asynchronously when called from ThisWillRunSyncTest public async Task RunTask() { Thread.Sleep(1000); } } 

Как правило, если у вас есть параллельная работа, вы должны использовать Parallel или параллельный LINQ.

Бывают случаи, когда удобно обрабатывать работу, связанную с ЦП, как если бы она была асинхронной (т. Е. Выполняла ее на фоновом streamе). Это то, для чего Task.Run (избегайте использования StartNew , как я описываю в своем блоге ).

Синхронные методы должны иметь синхронные сигнатуры методов:

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

Их нужно только обернуть в Task.Run если это требует код вызова (т. Task.Run Он является частью компонента пользовательского интерфейса, такого как модель представления):

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

Принцип здесь заключается в том, что Task.Run следует использовать в вызове, а не в реализации; Я подробно расскажу о своем блоге .

Обратите внимание: если у вас есть какая-то реальная сложность, вы должны использовать Parallel или параллельную LINQ вместо Task.Run задач Task.Run . Task.Run отлично подходит для небольших вещей, но у него нет всех умений, которые делают параллельные типы. Итак, если это часть библиотеки (и не обязательно работает в streamе пользовательского интерфейса), я бы рекомендовал использовать Parallel :

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

В качестве заключительного примечания стороны, асинхронные модульные методы тестирования должны быть async Task , а не async void . NUnit v3 уже удалил поддержку методов тестирования async void единиц.