async await: приостановлен ли основной поток?
Я читал о async/await
ключевые слова и я читал, что:
когда поток логики достигает токена await, вызывающий поток приостановлено до завершения вызова.
Ну, я создал простой windows forms application
, разместил две метки, кнопку и текстовое поле, и я написал код:
private async void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
button1.Text = await DoWork();
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private Task<string> DoWork()
{
return Task.Run(() => {
Thread.Sleep(10000);
return "done with work";
});
}
чего я не понимаю, это то, что когда я нажимаю кнопку, label1 будет иметь текст Running
и метка будет иметь тот же текст только через 10 секунд, но в эти 10 секунд я смог ввести текст в текстовое поле, поэтому кажется, что основной поток запущен...
Итак, как работает async/await?
в отношении
3 ответов
Я прочитал это: когда поток логики достигает токена await, вызывающий поток приостанавливается до завершения вызова.
где вы читали эту чушь? Либо там есть какой-то контекст, который вы не цитируете, либо вы должны прекратить читать любой текст, который содержит это. Смысл ожидания состоит в том, чтобы сделать напротив об этом. Точка ожидания чтобы текущий поток выполнял полезную работу, пока асинхронная задача в полете.
UPDATE: я загрузил книгу, на которую вы ссылались. Абсолютно все в этом разделе неправильно. Выбросьте эту книгу и купите книгу получше.
чего я не понимаю, так это того, что когда я нажимаю кнопку, label1 будет иметь текст, и метка будет иметь тот же текст только через 10 секунд, но в эти 10 секунд я смог ввести текст в мое текстовое поле, поэтому кажется, что основной поток бегущий...
это правильно. Вот что происходит:
label1.Text = Thread.CurrentThread.ThreadState.ToString();
текст.
button1.Text = await DoWork();
куча вещей происходит здесь. Что происходит в первую очередь? DoWork
называется. Что он делает?
return Task.Run(() => { Thread.Sleep(10000);
он захватывает поток из пула потоков, помещает этот поток в спящий режим на десять секунд и возвращает задачу, представляющую "работу", выполняемую этим потоком.
теперь мы вернулись здесь:
button1.Text = await DoWork();
у нас есть задача в руках. Await сначала проверяет задачу, чтобы увидеть, если она уже завершена. Это не. Затем он подписывает оставшуюся часть этого метода как продолжение задачи. Затем он возвращается к вызывающему.
Эй, кто его вызывающий? Как мы вообще сюда попали?
некоторый код вызвал этот обработчик событий; это был цикл событий, который обрабатывает сообщения Windows. Он увидел, что кнопка была нажата и отправлена обработчику click, который только что возвращенный.
что происходит? Цикл событий продолжает работать. Ваш UI продолжает работать хорошо, как вы заметили. В конце концов этот поток отсчитывает десять секунд, и продолжение задачи активируется. Что это значит?это отправляет сообщение в очередь Windows, говоря: "вам нужно запустить остальную часть этого обработчика событий сейчас; у меня есть результат, который вы искали."
цикл событий основного потока в конечном итоге попадает в это сообщение. Поэтому обработчик событий выбирает вверх, где он остановился:
button1.Text = await DoWork();
ожидание теперь извлекает результат из задачи, сохраняет его в тексте кнопки и возвращает обратно в цикл событий.
async
/await
создает машины состояния, которые обрабатывают продолжение для вас. Очень грубый эквивалент (без кучу функций) является явным методом продолжения, например:
private void button1_Click_Continuation(string value)
{
button1.Text = value;
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
DoWork(button1_Click_Continuation);
}
private void DoWork(Action<string> continuation)
{
Task.Run(() => {
Thread.Sleep(10000);
continuation("done with work");
});
}
обратите внимание, что я все еще использую Task.Run
для работы в отдельном потоке. Обратите внимание, что эта версия не имеет возможности отслеживать прогресс (в то время как оригинал может изменить возвращаемое значение button1_Click
до Task
чтобы увидеть, завершена ли она или нет).
в дополнение к вышесказанному преобразование система умна о том, является ли Task
запущен в потоке пользовательского интерфейса и Маршаллы обратно в поток пользовательского интерфейса снова, чтобы убедиться, что все работает так, как вы ожидаете. Это, вероятно, главное, что вы не поняли, но расширение аспекта государственной машины иногда объясняет, что asyc
/await
действительно означает (вместо того, чтобы оставить его как мистический).
писать await
, вы говорите - пожалуйста, остановите выполнение метода на этом этапе, подождите DoWork
закончить и только затем продолжить.
асинхронное программирование с async и await (C#) на что происходит в асинхронном методе раздел имеет пошаговое объяснение с изображением того, что происходит в async
метод.
еще лучшее объяснение в ожидание (ссылка на C#). Посмотрите комментарии для WaitSynchronously
и WaitAsynchronouslyAsync
ниже.
в статье также говорится (выделено мной):
оператор await применяется к задаче асинхронным методом для приостановки выполнения методом до тех пор, пока задача не завершится. Задача представляет собой текущую работу.
private async void button1_Click(object sender, EventArgs e)
{
// Call the method that runs asynchronously.
string result = await WaitAsynchronouslyAsync();
// Call the method that runs synchronously.
//string result = await WaitSynchronously ();
// Display the result.
textBox1.Text += result;
}
// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
await Task.Delay(10000);
return "Finished";
}
// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
// Add a using directive for System.Threading.
Thread.Sleep(10000);
return "Finished";
}