2015-07-03 2 views
2

Я прочитал, что я должен использовать только Result вместо await, когда я абсолютно уверен, что операция завершена. Я не совсем уверен, что происходит внизу, и хотел бы спросить опытных программистов, если это абсолютно безопасное использование await/Result/async.Тупик при использовании Результат

public static bool Success() 
{ 
    return 0 < Execute("DELETE FROM Table WHERE Id = 12").Result; 
} 

public static async Task<int> Execute(string sql) 
{ 
    using (var con = Connection) 
    { 
     con.Open(); 
     return await con.ExecuteAsync(sql); 
    } 
} 
+0

Возможный дубликат [ожидание работает, но вызывает задачу. Результат зависает/блокируется] (http://stackoverflow.com/questions/17248680/await-works-but-calling-task-result-hangs-deadlocks) – sstan

+0

'I что я должен использовать результат, а не ждать, когда я абсолютно уверен, что операция завершена. «Где вы это читали? Это совершенно неправильно. –

+0

@ StephenCleary хорошо ... это был ваш ответ здесь ... http://stackoverflow.com/questions/24623120/await-on-a-completed-task-same-as-task-result –

ответ

4

Это не безопасно. Операция еще не завершена, когда вы используете Task.Result

Когда вы вызываете метод async, он запускается синхронно, пока не достигнет ожидания, а затем возвращается к вызывающей стороне с задачей, которая представляет асинхронную операцию.

Задача не заполнена и использование Task.Result заблокирует вызывающий поток.

Вместо этого вы должны ждать возвращенной задачи или использовать синхронную опцию.

public static Task<bool> SuccessAsync() 
{ 
    return 0 < await ExecuteAsync("DELETE FROM Table WHERE Id = 12"); 
} 

public static async Task<int> ExecuteAsync(string sql) 
{ 
    using (var con = Connection) 
    { 
     con.Open(); 
     return await con.ExecuteAsync(sql); 
    } 
} 
+0

В сценариях вы не можете ждать, вы должны просто '.Wait()' в Задаче, или позволить Задаче выполнить свою задачу и добавить какой-нибудь дополнительный код, который вы хотите запустить как продолжение в выполняющейся задаче. Вы не всегда можете ждать, бывают случаи, когда это не вариант –

+3

@JohnathonSullinger, выполняющий '.Wait()' так же плохо, как делать '.Result'. ** В ситуациях, когда вы не можете ждать, вы не должны использовать async/await в любом месте этого стека вызовов **. Вместо этого вы должны выполнять синхронные вызовы. –

+0

'.Wait()' не вызовет мертвую блокировку? Бывают моменты, когда вы не можете обойти это. Пример, с которым я столкнулся в последнее время, был обработчиком событий void в пользовательском интерфейсе, который мне приходилось называть сторонним асинхронным методом. Если я сделал метод «async void», процесс завершения просмотра продолжился, и я не смог завершить свое взаимодействие с сторонней структурой. Бывают случаи, когда вам приходится ждать из-за вещей, которые вы не контролируете. –

3

Это безопасно, хотя в конце концов блокирует, пока Execute не будет завершена. Доступ к Task.Result эквивалентно:

Task<int> task = Execute("..."); 
task.Wait(); // blocks until done 
return 0 < task.Result; 

Если вы хотите, чтобы далее await цепь, вы могли бы Success вернуть Task<bool> вместо этого.

Обратите внимание, что существует вероятность блокировки в зависимости от тока SynchronizationContext. Если ваш SynchronizationContext является однопоточным, тогда ваш вызов Task.Result заканчивается блокировкой и ждет завершения Execute, но Execute ждет вас, чтобы выпустить поток, чтобы он мог продолжить. Если вы используете графическое приложение (с использованием однопоточного SynchronizationContext по умолчанию) или ASP.NET, то вам стоит подумать о добавлении ConfigureAwait(false), чтобы вместо этого выполнить поток нитей пула потоков Execute.

+0

Как это безопасно? – i3arnon

+0

@ i3arnon - я классифицирую его как «безопасный», так как нет неопределенного поведения или исключения. Блокировка небезопасна, так оно и есть - иногда вы этого хотите, иногда нет. –

+0

И тупик? – i3arnon

Смежные вопросы