【问题标题】:async/await deadlock without using Task.Result不使用 Task.Result 的异步/等待死锁
【发布时间】:2016-03-24 10:17:52
【问题描述】:

我有一个一直使用 async/await 的 web api:

public class SampleController : ApiController
{
    public async Task<IEnumerable<DocumentModel>> GetAll()
    {
        List<DocumentModel> modelItems = new List<DocumentModel>();

        var response = await SearchDocumentsAsync();
        var items = response.Results.ToList();
        foreach(var document in documents)
        {
            var model = new DocumentModel()
            {
                Id = document.Id,
                Name = document.Name
            };

            modelItems.Add(model);
        }

        return modelItems;
    }

    private Task<DocumentSearchResponse<Document>> SearchDocumentsAsync()
    {
        using (var searchClient = new SearchServiceClient(new SearchCredentials(searchServiceKey), searchServiceUri))
        using (var indexClient = searchClient.Indexes.GetClient(indexName))
        {
            var parameters = new SearchParameters()
            {
                IncludeTotalResultCount = true
            };

            // call the Azure Search service
            return indexClient.Documents.SearchAsync<Document>(search.Term, parameters);
        }
    }    
}

我没有在调用堆栈中的任何地方使用.Wait().Result。这样的代码还有可能死锁吗?当我调试这段代码时,我似乎正在经历一个,但对于我的一生,我无法弄清楚为什么。

我使用 Postman 发送了几个请求,但有时响应永远不会回来。如果我按下调试器中的暂停按钮,它将显示一条绿色的行,上面写着“这是当该线程从当前函数返回时要执行的下一条语句。”当我按下暂停按钮时,代码的位置并不一致,但似乎一旦其中一个请求被阻止,其他所有请求都会被阻止。

上面的代码会死锁吗?

【问题讨论】:

  • 调试代码时,执行在哪里停止?您还需要提供一个完整的示例来复制问题,以便我们能够提供解决方案。
  • 也就是说,死锁可能由很多原因引起,在异步操作尝试向其发布延续时同步阻塞同步上下文只是导致死锁的一种方式。还有很多其他的。
  • 我提到它在哪里停止并不一致。我对上面的代码更感兴趣。上面的代码中是否有任何操作会导致死锁?
  • 您基本上没有显示任何代码;没有办法说有没有问题。
  • @Servy 我更新了代码。我正在使用 Azure 搜索 REST api。我使用 .net 库调用 REST API 并等待调用...然后我使用从文档返回的一些 get/set 属性构建模型。

标签: c# asynchronous asp.net-web-api async-await


【解决方案1】:

SearchDocumentsAsync 中,您会立即从SearchAsync 返回任务。

您应该等待此任务,以确保在操作完成之前不会释放 indexClientsearchClient。这些被释放可能是导致死锁的原因。

【讨论】:

  • 如果我将代码更改为在 SearchDocumentsAsync 方法中添加 async / await 而不是返回任务,但我删除了 using 语句并在 ApiController.Dispose 方法中处理它们,我会遇到任何类似的问题?
  • @Dismissile 我不太了解 MVC,多个线程可以同时调用 SearchDocumentsAsync 的同一个实例吗?如果是这样,您可能会在那里遇到问题。但是,如果一次只有一个线程访问该实例,您应该可以将创建移至构造函数并将处置移至类的Dispose()。注意:如果您有不需要创建客户端的方法,您可能会在其他调用中引入不必要的开销。
  • @ScottChamberlain mvc 中的每个请求都有自己的实例,所以这不太可能
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-22
  • 2021-09-18
相关资源
最近更新 更多