C# 为什么WhenAll会用多个ping不确定地等待?

C# 为什么WhenAll会用多个ping不确定地等待?,c#,.net,multithreading,ping,C#,.net,Multithreading,Ping,我的应用程序需要ping网络中所有可能的IP地址。由于IP列表很大(大约4000个条目),我决定异步执行ping以加快进程。我最初编写的代码似乎工作得很好,但不知何故,当我昨天尝试它时,它不再像预期的那样工作了(可能是在一些.NET更新之后?我真的不知道) 我的代码是这样工作的:从IP地址列表中,我创建了一个任务列表(每个IP一个),然后将任务列表传递给WhenAll,等待所有ping请求完成。问题是有时WhenAll会无限期地等待(我用调试器检查了它,发现传递给WhenAll的一些任务始终处于

我的应用程序需要ping网络中所有可能的IP地址。由于IP列表很大(大约4000个条目),我决定异步执行ping以加快进程。我最初编写的代码似乎工作得很好,但不知何故,当我昨天尝试它时,它不再像预期的那样工作了(可能是在一些.NET更新之后?我真的不知道)

我的代码是这样工作的:从IP地址列表中,我创建了一个任务列表(每个IP一个),然后将任务列表传递给WhenAll,等待所有ping请求完成。问题是有时WhenAll会无限期地等待(我用调试器检查了它,发现传递给WhenAll的一些任务始终处于“等待激活”状态)。奇怪的是,有时(在3次测试中大约2次)它会按预期工作,并且所有任务都会完成

以下是我使用的代码:

    public static async Task<List<PingReply>> PingAsync(List<IPAddress> ips, int timeout)
     {
         var pingTasks = ips.Select(ip =>
         {
             using (Ping ping = new Ping())
             {
                 return ping.SendPingAsync(ip, timeout);
             }
         });
    
         var results = await Task.WhenAll(pingTasks);
    
         return results.ToList();
     }
公共静态异步任务PingAsync(列出IP,int超时)
{
var pingTasks=ips.Select(ip=>
{
使用(Ping=new Ping())
{
返回ping.SendPingAsync(ip,超时);
}
});
var结果=等待任务.WhenAll(pingTasks);
返回结果。ToList();
}

关于问题可能是什么的任何提示?

问题可能是您正在处理
ping
,而从
SendPingAsync
返回的
任务可能尚未完成。这将是一场激烈的比赛,这也许可以解释为什么你会看到这种不可预测的情况发生

在处理
ping
之前,请尝试等待该
任务:

public static async Task<List<PingReply>> PingAsync(List<IPAddress> ips, int timeout)
{
    var pingTasks = ips.Select(async ip =>
    {
        using (Ping ping = new Ping())
        {
            return await ping.SendPingAsync(ip, timeout);
        }
    });

    var results = await Task.WhenAll(pingTasks);

    return results.ToList();
}
公共静态异步任务PingAsync(列出IP,int超时)
{
var pingTasks=ips.Select(异步ip=>
{
使用(Ping=new Ping())
{
返回wait ping.SendPingAsync(ip,超时);
}
});
var结果=等待任务.WhenAll(pingTasks);
返回结果。ToList();
}

请注意,在从
SendPingAsync
返回的
Task
完成之前,您已经处理了
ping
,但无论如何,您没有使用
ping
,因此您的第二个bug避免了第一个bug。。。可能这个问题是您没有处理(第二个)
new Ping()
?我不确定它使用的是什么非托管资源。对不起,我只是看到我混合了两个版本的代码(我尝试了很多方法)。我将编辑问题以删除不必要的第二个Ping。但是如何在任务返回后正确处理Ping实例呢?在代码的编辑版本中,您可能在
SendPingAsync
完成之前处理
Ping
,从而导致不可预测的行为。只需将匿名函数传递给Select async-
async ip=>。。。return wait ping.SendPingAsync
另请参见。在等待
SendPingAsync
时,您正在失去并行性,不是吗?这就是
的目的,当所有的
第一个示例都无法编译,而第二个示例将失败,因为
Ping
类不支持来自同一实例的并发Ping。@Phate01否。如果我在
ips
上有一个循环,并且
等待
在一个循环中,那么你是对的,但这是在创建一个
异步
函数(其中包含使用的
等待的
),多次调用它,然后在一次调用中等待生成的
任务go@Evk修复了丢失的
返回值
。我不确定是否存在一致性,因此警告被删除。谢谢,这肯定是问题所在,因为现在它似乎总是工作正常。这也解释了我的奇怪行为,正如你提到的。