#c#
#c#
Вопрос:
У меня есть мой файл Program.cs:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace AsyncTest
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var interesting = new InterestingObject();
List<int> list;
List<int> alsoList;
list = await interesting.GenerateListAsync();
alsoList = interesting.GenerateList();
Console.WriteLine("Done! :)");
list .ForEach(xs => Console.WriteLine(xs));
alsoList.ForEach(xs => Console.WriteLine (xs));
}
}
}
И вот код для InterestingObject:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncTest
{
public class InterestingObject
{
public InterestingObject()
{
}
public List<int> GenerateList()
{
Console.WriteLine("Gonna generate the list!");
var list = new List<int>();
int i = 0;
while (i < 5)
{
Random random = new Random();
list.Add(random.Next());
Console.WriteLine("Generated a new int!");
VeryHeavyCalculations();
i ;
}
return list;
}
public async Task<List<int>> GenerateListAsync()
{
Console.WriteLine("Gonna generate the list async!");
var list = new List<int>();
int i = 0;
while (i < 5)
{
Random random = new Random();
list.Add(random.Next ());
Console.WriteLine("Generated a new int asyncronously!");
await Task.Run(() => VeryHeavyCalculations());
i ;
}
return list;
}
public void VeryHeavyCalculations()
{
Thread.Sleep (1000);
}
}
}
Я ожидаю, что list = await interesting.GenerateListAsync();
во время alsoList = interesting.GenerateList();
выполнения будет выполняться асинхронно, эффективно регистрируя выходные данные GenerateList
в моей консоли, пока GenerateListAsync
выполняется то же самое, или чтобы увидеть GenerateListAsync
завершение почти мгновенно по GenerateList
завершении.
Однако, заглядывая в консоль, я вижу, что мое приложение запущено, GenerateListAsync
а затем запускается GenerateList
после этого.
Я делаю это неправильно, но ни одного источника не было достаточно для решения этой проблемы.
Комментарии:
1. Он выполняется асинхронно, но код не продолжается до окончания
await
. Если вы хотите завершить эту операцию и затем двигаться дальше, то неawait
выполняйте задачу до некоторого момента позже в вашем коде.2. Это вспомогательный ответ на ваш вопрос. Вы делаете
new Random()
в цикле. Для вас это ничем хорошим не закончится. Вы просто собираетесь создать его с тем же исходным кодом, и он будет генерировать те же числа.3. @Crowcoder вы хотите сказать, что компилятор использует предварительный просмотр, чтобы увидеть, есть ли
await
впереди, и он будет запускать их асинхронно, пока он выполняет весь предшествующий ему код?4. Нет. Вы могли бы рассмотреть возможность загрузки LINQPad и ознакомления с этим руководством по библиотеке примеров: Интерактивное руководство по асинхронности в C # 5, обновленное для Framework 4.5 RTM
Ответ №1:
Я ожидаю, что
list = await interesting.GenerateListAsync();
будет выполняться асинхронно во времяalsoList = interesting.GenerateList();
выполнения,
Это ожидание неверно; весь смысл await
в том, что оно не продолжается после этой точки, пока асинхронная операция не будет завершена; это делается с помощью ряда уловок, включая асинхронные конечные автоматы, которые позволяют возобновить незавершенную операцию, когда возвращаются результаты. Однако вы можете просто переместить точку, в которой вы await
находитесь, чтобы это не вызвало этой предполагаемой блокировки:
List<int> list;
List<int> alsoList;
var pending = interesting.GenerateListAsync(); // no await
alsoList = interesting.GenerateList();
list = await pending; // essentially "joins" at this point... kind of
Обратите внимание, что async
и параллелизм — это разные вещи; их можно использовать вместе, но по умолчанию это происходит не так. Также обратите внимание: не весь код разработан для обеспечения одновременного использования, поэтому вам не следует делать такого рода вещи, не зная, нормально ли использовать параллельные вызовы в определенном API.
Комментарии:
1. Ах, я думаю, я только сейчас понял ..
await
используется не для указания чему-либо выполняться асинхронно, а для ожидания операций, которые выполняются асинхронно?2. @Vanitas точно
3. Итак, что тогда произойдет, если вы используете
async
при объявлении элемента объекта? Есть ли у вас источник, который подробно объясняет, что именно происходит?4. @Vanitas
async
буквально ничего не делает, кроме включенияawait
ключевого слова; что касается того, что происходит, когда выawait
— это действительно сложная история5. Поддержано. Не понимаю, в чем разница. Это краткое и точное объяснение того, как работает шаблон
async
/await
, который был проблемой в исходном сообщении.
Ответ №2:
В дополнение к ответу взгляните на await (ссылка на C #)
Оператор await применяется к задаче в асинхронном методе, чтобы вставить точку приостановки в выполнение метода до завершения ожидаемой задачи. это причина, по которой в вашем приложении выполняется GenerateListAsync, а затем выполняется GenerateList впоследствии. Чтобы запустить GenerateListAsync асинхронно, вам нужно принять возвращаемое значение GenerateListAsync в переменной задачи, а затем вызвать GenerateList и после этого использовать метод await для GenerateListAsync.
например
Task <List<int>> longRunningTask = interesting.GenerateListAsync();
alsoList = interesting.GenerateList();
list = await longRunningTask;
Комментарии:
1. » Для асинхронного запуска GenerateListAsync … » — Вы путаете асинхронность с параллелизмом. Оно выполняется асинхронно (при условии, что реализовано как таковое) даже с await .