获取主机条目异步冻结

时间:2014-07-07 12:55:55

标签: c# asynchronous

我将代码部署到生产服务器时出现问题。它不会在我的计算机上本地发生。当我运行该行

var host = await Dns.GetHostEntryAsync(adresse);

生产环境冻结或等待无限期。为什么会这样?

以下是代码:

    public async Task<string> HentAsync(string ip)
    {
        if (string.IsNullOrWhiteSpace(ip) || kLoopbackIp.Contains(ip))
        {
            return string.Empty;
        }

        if (IpHostname.ContainsKey(ip))
        {
            UpdateAndRemoveOldElements(ip);

            return IpHostname[ip].Item1;
        }

        try
        {
            IPAddress adresse = IPAddress.None;
            if (!IPAddress.TryParse(ip, out adresse))
            {
                return string.Empty;
            }

            var host = await Dns.GetHostEntryAsync(adresse);
            string hostname = host.HostName;

            IpHostname.AddOrUpdate(ip,
                                   new Tuple<string, DateTime>(hostname, DateTime.Now),
                                   (x, y) => new Tuple<string, DateTime>(hostname, DateTime.Now));
            return hostname;
        }
        catch (Exception)
        {
            // Tar i mot exception og returnerer tom string
            return string.Empty;
        }
    }

更新: async方法就像这样从一个同样的方法调用(这可能是罪魁祸首)。

public string Hent(string ip)
{
    return HentAsync(ip).Result;
}

1 个答案:

答案 0 :(得分:1)

最可能的原因是此调用的来源在UI线程上运行;也许调用Hent()更新UI元素?

此问题已在此处详细记录:await works but calling task.Result hangs/deadlocks

Hent()拨打HentAsync(),然后拨打await Dns.GetHostEntryAsync()。这最后一个调用产生一个新线程,但想要在完成后返回调用线程,在这种情况下是UI线程,但它不能这样做,因为.Result蹲在线程上而不是让它产生它暂时与await一样。

正如@spender和@Dirk所指出的,一个解决方案是将.ConfigureAwait(false)添加到await Dns.GetHostEntryAsync()。实际上,您应该将此添加到您不关心函数继续的线程上下文的每个await

这种方法仍然非常脆弱,因为任何时候你忘记这样做或执行采用未经修改的await的路径,问题将再次发生。最好的选择是使每个函数调用产生顶级UI线程函数async然后await,这可能会导致延迟。这是async / await的规范用例,导致平坦,易于遵循的代码,几乎没有死锁的可能性。