Web Forms应用从SQL数据库读取IP批量ping时如何避免网络变慢
Ping功能性能优化方案
现有代码核心问题
- 资源泄漏:
Ping类实现了IDisposable接口,当前代码每次循环新建Ping实例后未主动释放,长期运行会累积大量未释放的非托管网络资源,拖慢系统甚至网络栈性能。 - 同步阻塞效率低:使用同步
Send方法逐个ping IP,默认超时为5秒,50个IP最坏情况下一轮需要250秒,还会长期占用ASP.NET工作线程,引发服务端性能下降。 - 控件无限累加:每次执行方法时直接往
ServerPanel、OverViewUpdate容器中新增控件,未清理旧控件,长期运行会导致页面视图状态、内存占用持续上涨,表现为页面加载慢、服务端响应卡。 - 频繁更新局部视图:每遇到一个异常/超时IP就调用一次
Panel.Update(),重复触发局部刷新,额外增加开销。 - ping频率过高:未限制ping的间隔和超时时间,若轮询间隔过短会导致网络中ICMP包占比过高,挤占正常业务带宽。
优化方案
- 用
using块包裹Ping实例,用完自动释放资源,从根源避免资源泄漏。 - 改用异步
SendPingAsync并行执行所有ping请求,一轮总耗时仅等于最慢的单个ping耗时,同时不阻塞工作线程。 - 每次执行ping逻辑前先清空对应容器的旧控件,避免资源无限累积。
- 自定义ping超时时间(建议设为1000ms),无需等待默认的5秒超时,同时将轮询间隔调整到1-5分钟,设备在线状态无需秒级刷新的场景下完全够用。
- 所有IP ping处理完成后统一调用一次局部刷新,减少重复开销。
优化后代码示例
首先需要在对应.aspx页面头部的Page指令中添加Async="true"属性,开启页面异步支持,后端代码修改如下:
private async Task NetworkDevices() { // 先清空概览面板旧内容 OverViewUpdate.Controls.Clear(); var pingTasks = new List<Task<(string Ip, string Host, PingReply Reply, GridViewRow Row)>>(); // 先收集所有ping任务 foreach (GridViewRow row in GridViewServer.Rows) { if (row.RowType != DataControlRowType.DataRow) continue; // 先清空每行的面板旧内容 var serverPanel = (Panel)row.FindControl("ServerPanel"); serverPanel.Controls.Clear(); string destIP = GridViewServer.DataKeys[row.RowIndex].Value.ToString(); string destHost = row.Cells[2].Text; // 添加异步ping任务 pingTasks.Add(PingSingleDevice(destIP, destHost, row)); } // 并行等待所有ping完成 var results = await Task.WhenAll(pingTasks); // 统一处理结果更新UI foreach (var res in results) { var serverPanel = (Panel)res.Row.FindControl("ServerPanel"); Image statusImg = new Image(); if (res.Reply == null) { // ping异常 statusImg.ImageUrl = "../Images/red.png"; statusImg.ToolTip = "ping请求异常"; serverPanel.Controls.Add(statusImg); // 添加到异常概览 OverViewUpdate.Controls.Add(new Image { ImageUrl = "../Images/red.png" }); OverViewUpdate.Controls.Add(new Label { Text = $"{res.Host} ping请求异常<br/>" }); } else if (res.Reply.Status == IPStatus.Success) { if (res.Reply.RoundtripTime > 50) { statusImg.ImageUrl = "../Images/yellow.png"; statusImg.ToolTip = $"RoundTripTime: {res.Reply.RoundtripTime}ms"; serverPanel.Controls.Add(statusImg); // 添加到异常概览 OverViewUpdate.Controls.Add(new Image { ImageUrl = "../Images/yellow.png" }); OverViewUpdate.Controls.Add(new Label { Text = $"{res.Host} RoundTripTime: {res.Reply.RoundtripTime}ms<br/>" }); } else { statusImg.ImageUrl = "../Images/green.png"; statusImg.ToolTip = $"RoundTripTime: {res.Reply.RoundtripTime}ms"; serverPanel.Controls.Add(statusImg); } } else { statusImg.ImageUrl = "../Images/red.png"; statusImg.ToolTip = res.Reply.Status.ToString(); serverPanel.Controls.Add(statusImg); // 添加到异常概览 OverViewUpdate.Controls.Add(new Image { ImageUrl = "../Images/red.png" }); OverViewUpdate.Controls.Add(new Label { Text = $"{res.Host} {res.Reply.Status}<br/>" }); } } // 统一更新一次局部视图 OverViewUpdate.Update(); } // 单个设备ping逻辑 private async Task<(string Ip, string Host, PingReply Reply, GridViewRow Row)> PingSingleDevice(string ip, string host, GridViewRow row) { using (Ping p = new Ping()) { try { // 超时设为1000ms,可按需调整 var reply = await p.SendPingAsync(ip, 1000); return (ip, host, reply, row); } catch { return (ip, host, null, row); } } }
内容的提问来源于stack exchange,提问作者user14568805
相关产品推荐
相关产品推荐

