批量Ping 167个IP耗时过长问题求助(.NET 8)
问题分析与解决方案
核心原因:串行执行Ping请求
你当前的代码在foreach循环里逐个await每个Ping操作,导致所有请求串行执行——前一个Ping完成(或超时)后,才会发起下一个。这就是实际耗时远超理论值的根本原因:160个超时IP的耗时是逐个累加的,而非并行执行的总和。
解决方法:并行执行所有Ping请求
改用Task.WhenAll批量并行处理所有Ping任务,让多个Ping请求同时发起,大幅降低总耗时。
修改后的核心代码示例
var model = await _toyCityService.GetToyCityViewModel(); // 收集所有需要执行Ping的任务,每个任务返回关联的item和Ping结果数据 var pingTasks = model .Where(item => !string.IsNullOrEmpty(item.DevIPWIFI)) .Select(async item => { bool? pingable = false; try { using var ping = new Ping(); var reply = await ping.SendPingAsync(item.DevIPWIFI, 100); if (reply.Status == IPStatus.Success) { long lastDateTimeRec = item.LastDateTimeRec == null ? 0 : Convert.ToInt64(item.LastDateTimeRec); var timeMinusFive = DateTime.Now.AddMinutes(-5).ToFileTime(); pingable = timeMinusFive < lastDateTimeRec ? true : null; } else { pingable = false; } } catch { pingable = false; } return new PingResult() { Id = item.ID, IP = item.DevIPWIFI, Status = pingable }; }) .ToList(); // 等待所有并行任务完成 var res = await Task.WhenAll(pingTasks); return res.ToList();
关键优化点说明
- 并行执行:通过
Select创建所有Ping任务,再用Task.WhenAll等待全部完成,所有Ping请求同时发起,总耗时接近单个请求的最长耗时(而非累加)。 - 资源管理:使用
using声明自动释放Ping实例,避免资源泄漏。 - 关联数据:每个任务直接返回对应
item的PingResult,无需额外处理顺序问题。
额外注意事项
- 系统ICMP限制:Windows默认对ICMP请求有并发数限制,如果并行数量过大,可能会被系统限流,导致部分请求延迟。可以尝试限制并行度(比如用
Parallel.ForEach并设置MaxDegreeOfParallelism,或者用SemaphoreSlim控制并发数)。 - 超时时间实际生效:注意
SendPingAsync的超时参数是单次请求的超时时间,底层可能存在重试逻辑(取决于系统设置),如果需要严格控制超时,可以检查系统的ICMP重试配置。
内容的提问来源于stack exchange,提问作者Ali Jebali
相关产品推荐
相关产品推荐

