使用Result时出现死锁

时间:2015-07-03 20:30:07

标签: c# .net asynchronous async-await

我已经读过,当我完全确定操作已完成时,我应该只使用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);
    }
}

2 个答案:

答案 0 :(得分:4)

这不安全。使用Task.Result

时,操作尚未完成

当你调用异步方法时,它会同步运行,直到它到达await,然后返回给调用者,并带有代表异步操作的任务。

任务未完成,使用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);
    }
}

答案 1 :(得分: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正在等待您释放该线程,它可以继续。如果您使用的是GUI应用程序(默认情况下使用单线程SynchronizationContext)或ASP.NET,那么您是否要考虑添加ConfigureAwait(false)以使Execute运行在而不是线程池线程。