Ожидание ключевых слов
Итак, у меня есть следующий код
private async void button1_Click(object sender, EventArgs e)
{
await DoSomethingAsync();
MessageBox.Show("Test");
}
private async Task DoSomethingAsync()
{
for (int i = 0; i < 1000000000; i++)
{
int a = 5;
}; // simulate job
MessageBox.Show("DoSomethingAsync is done");
await DoSomething2Async();
}
private async Task DoSomething2Async()
{
for (int i = 0; i < 1000000000; i++)
{
int a = 5;
} // simulate job
MessageBox.Show("DoSomething2Async is done");
}
Пока оба MessageBoxes не показаны, основной поток является блоком (я имею в виду, что само приложение заморожено). Очевидно, что-то не так с моим кодом, и я не могу понять, что. Я никогда раньше не использовал async/await. это моя первая попытка.
EDIT:
Фактически, что я хочу сделать, это запустить асинхронное выполнение DoSomethingAsync
, чтобы при нажатии кнопки MessageBox.Show("Test");
выполнялся, даже если DoSomethingAsync является неполным.
Ответы
Ответ 1
Я думаю, вы неправильно поняли, что такое асинхронное средство. Это не значит, что метод работает в другом потоке!
Асинхронный метод выполняется синхронно до первого await
, а затем возвращает Task
вызывающему (если только он не async void
, то он ничего не возвращает). Когда ожидаемая задача завершается, выполнение возобновляется после await
, как правило, в том же потоке (если у него есть SynchronizationContext
).
В вашем случае Thread.Sleep
находится перед первым ожиданием, поэтому он выполняется синхронно, прежде чем управление возвращается вызывающему. Но даже если это было после await
, он все равно блокирует поток пользовательского интерфейса, если только вы не настроили awaiter не на захват контекста синхронизации (используя ConfigureAwait(false)
).
Thread.Sleep
- метод блокировки. Если вы хотите использовать асинхронный эквивалент, используйте await Task.Delay(3000)
, как указано в ответе Шрирама Сактивеля. Он немедленно вернется и возобновится через 3 секунды, не блокируя поток пользовательского интерфейса.
Это распространенное заблуждение, что async связан с многопоточным. Это может быть, но во многих случаях это не так. Новый поток неявно порождается только потому, что метод async
; для создания новой нити, это должно быть сделано явно в какой-то момент. Если вы специально хотите, чтобы метод работал в другом потоке, используйте Task.Run
.
Ответ 2
Вы должны заметить, что методы, отмеченные async
, больше не будут вести себя async, если ему не хватает await
. У вас было бы предупреждение о компиляторе.
Предупреждение 1 В этом асинхронном методе отсутствуют операторы "ждут" и будут выполняться синхронно. Рассмотрите возможность использования оператора ожидания неблокирующие вызовы API или "ждут Task.Run(...)" для работы с ЦП на фоновом потоке.
Вы должны обратить внимание на эти предупреждения.
Сделайте это асинхронно. Когда я говорю асинхронно, это действительно асинхронное несинхронное задание в другом потоке.
Используйте Task.Delay
, который действительно асинхронен. Используйте Task.Run
для некоторого трудоемкого задания, которое связано с ЦП.
private async void button1_Click(object sender, EventArgs e)
{
await DoSomethingAsync();
}
private async Task DoSomethingAsync()
{
await Task.Delay(3000); // simulate job
MessageBox.Show("DoSomethingAsync is done");
await DoSomething2Async();
}
private async Task DoSomething2Async()
{
await Task.Delay(3000); // simulate job
MessageBox.Show("DoSomething2Async is done");
}
Ответ 3
Вы ничего не делаете асинхронно. Попробуйте:
await Task.Run(() => Thread.Sleep(3000))
Когда вы ожидаете метода, то, что вы эффективно делаете, это обеспечение обратного вызова с кодом, который следует за ним, как то, что выполняется после его завершения (в предыдущих воплощениях async вам действительно нужно было установить это самостоятельно). Если вы не await
ничего, то метод на самом деле не является асинхронным.
Для получения дополнительной информации вы можете сделать хуже, чем здесь:
http://msmvps.com/blogs/jon_skeet/archive/2011/05/08/eduasync-part-1-introduction.aspx
После редактирования; попробуйте следующее:
public void MyMessageBox()
{
var thread = new Thread(() =>
{
MessageBox.Show(...);
});
thread.Start();
}
Хотя, вы уверены, что это действительно окно сообщения, которое вы хотите? Я бы подумал, что обновление строки состояния/индикатора выполнения улучшится.
Ответ 4
В DoSomethingAsync
Thread.Sleep
вызывается до await
, а в DoSomething2Async
не выполняется асинхронная задача.