以下启用异步的代码是否容易导致死锁

时间:2015-03-05 15:09:26

标签: c# asynchronous task-parallel-library async-await task

    public async Task<Foo> Execute(int id)
    {
        var parameters = new { id};

        using (var con = new SqlConnection(this.connectionString))
        {
            await con.OpenAsync();

            return await con.QueryAsync<foo>(
                "dbo.uspGetMeFoo",
                parameters,
                commandType: CommandType.StoredProcedure,
                commandTimeout: int.Parse(ConfigurationManager.AppSettings["SqlCommandTimeout"]))
                .ContinueWith(task =>  task.Result.FirstOrDefault());
        }
    }

在调用类中等待这个方法,其中 - 在一段时间之后 - 我想在不明确阻塞的情况下使用结果。

我可以通过在调用代码中返回ContinueWithTask<IEnumerable<Foo>>来解决此问题,以便不使用上面的FirstOrDefault()

从我所看到的上面的阻塞是臭的,更糟糕​​的是会导致问题,可能是一个僵局。我对么?

2 个答案:

答案 0 :(得分:5)

在已完成的Result上调用Task知道,如果其继续触发,任务将完成)不会导致死锁。

当任务需要能够在另一个线程/上下文上调度操作以便能够完成时,会导致死锁,但该线程/上下文在结果上阻塞。由于任务已经完成,阻塞线程/上下文不可能阻止它完成。

也就是说,您可以轻松地await完成任务,而不是致电ContinueWith

答案 1 :(得分:1)

正如@Servy所说,你可以轻松地写

public async Task<Foo> Execute(Foo foo )
{
    var parameters = new { id = id};

    using (var con = new SqlConnection(this.connectionString))
    {
        var timeout = int.Parse(
            ConfigurationManager.AppSettings["SqlCommandTimeout"]);

        await con.OpenAsync();

        var query = await con.QueryAsync<Foo>(
            "dbo.uspGetMeFoo",
            parameters,
            commandType: CommandType.StoredProcedure,
            commandTimeout: timeout);

        return query.FirstOrDefault();
    }
}

除非dbo.uspGetMeFoo做出意外和愚蠢的事情,否则这不会导致死锁。这不会是问题中代码的问题。