任务“尚未计算”:在异步操作仍处于挂起状态时完成异步模块或处理程序

时间:2013-11-28 16:53:16

标签: c# wcf entity-framework asynchronous .net-4.5

一直在优化客户端搜索功能,这样他就可以一次执行多次搜索,而不会影响加载时间(至少不会太多)。 搜索的工作方式是我们首先获取外部服务的json,将其转换为datacontract,然后将其保存在数据库中并返回实体对象。

之前,我在一个方法中完成了所有这一切,并成功地异步加载了几个搜索但是如果我可以分离服务调用,将json从保存它的部分分离到我们自己的数据库并返回对象然后它应该能够更快,因为搜索服务实际上是真正的搜索。

所以现在我有两个OperationContracts:

    [OperationContract]
    SwepubHeader DoSwepubSearchAdvanced(string searchQuery, string hiddenSearchWord, Dictionary<string, string> advancedSearchParameters);

    [OperationContract]
    List<List<SearchItem>> GetSearchResults(List<SwepubHeader> headers);

第一个进入名为swepub的搜索服务并重新调用json调用并将其解析为DataContract 第二个将数据保存到数据库并将数据作为EntityFramework对象返回。用户可以发送几个SwepubHeader-DataContract,然后获得几个搜索结果

在我想要进行异步调用的网站中,我的代码如下所示:

    List<Task<SwepubHeader>> _taskList = new List<Task<SwepubHeader>>();

    public SwepubHeader[] DoSearchAdvanced(SwepubSearchServiceClient client, string query,
        string[] subQuerys, Dictionary<string, string> advancedSearchParameters)
    {
        _taskList = new List<Task<SwepubHeader>>();
        DoSearchAdvancedAsync(client, query, subQuerys, advancedSearchParameters);

        return _taskList.Select(task => task.Result).ToArray();
    }
    private async void DoSearchAdvancedAsync(SwepubSearchServiceClient client, string query, IEnumerable<string> subQuerys, Dictionary<string, string> advancedSearchParameters)
    {
        foreach (string subQuery in subQuerys)
        {
            if (!string.IsNullOrWhiteSpace(subQuery))
            {
                // Starts an async search
                _taskList.Add(client.DoSwepubSearchAdvancedAsync(query, subQuery,
                    advancedSearchParameters));
            }
        }
        // Awaits all async searches to finish
        await Task.WhenAll(_taskList);
    }

代码失败于:

return _taskList.Select(task => task.Result).ToArray();

我错过了什么?所有task.Result将显示“尚未计算”。是否与我在DoSwepubSearchAdvanced中执行HttpWebRequests有关?

1 个答案:

答案 0 :(得分:4)

您遇到的问题是由于您使用了async void。作为一般规则,您应该避免async void; see my MSDN article for more information

您的设计还有另一个问题:it's not a good idea to wrap asynchronous methods within synchronous methods。一旦解决了async void个问题,您仍然会得到deadlock issues that I describe on my blog

正确的解决方案是使用异步方法替换DoSearchAdvanced

public Task<SwepubHeader[]> DoSearchAdvancedAsync(
    SwepubSearchServiceClient client,
    string query, string[] subQuerys,
    Dictionary<string, string> advancedSearchParameters)
{
  return Task.WhenAll(subQuerys
      .Where(subQuery => !string.IsNullOrWhiteSpace(subQuery))
      .Select(subQuery => client.DoSwepubSearchAdvancedAsync(
          query, subQuery, advancedSearchParameters)));
}

然后将您的网站调用修改为await结果。