Estoy trabajando en una aplicación de "latido" que hace ping a cientos de direcciones IP cada minuto a través de un bucle. Las direcciones IP se almacenan en una lista de Machines de una clase. Tengo un ciclo que crea una Task<MachinePingResults> (donde MachinePingResults es básicamente una Tupla de una IP y un estado en línea) para cada IP y llama a una función de ping usando System.Net.NetworkInformation .
El problema que tengo es que después de horas (o días) de ejecución, uno de los bucles del programa principal no puede finalizar las Tasks , lo que provoca una pérdida de memoria. No puedo determinar por qué mis tareas no están finalizando (si miro en la lista de tareas durante el tiempo de ejecución después de unos días de ejecución, hay cientos de tareas que aparecen como "esperando"). La mayoría de las veces todas las tareas terminan y se desechan; es solo al azar que no terminan. Por ejemplo, las últimas 24 horas tuvieron un problema a las 12 horas con 148 tareas en espera que nunca terminaron. Debido a la naturaleza de no poder ver por qué el Ping se bloquea (dado que es interno de .NET), no he podido replicar el problema para depurar.
( Parece que la llamada Ping en .NET puede bloquearse y el tiempo de espera incorporado falla si hay un problema de DNS, razón por la cual incorporé un tiempo de espera adicional)
Tengo una forma de cancelar el ciclo principal si los ping no regresan dentro de los 15 segundos usando Task.Delay y CancellationToken . Luego, en cada función de Ping, tengo un Delay en caso de que la llamada de Ping se cuelgue y obliga a que la función se complete. También tenga en cuenta que solo estoy haciendo ping a IPv4; no hay IPv6 o URL.
Bucle principal
pingcancel = new CancellationTokenSource(); List<Task<MachinePingResults>> results = new List<Task<MachinePingResults>>(); try { foreach (var m in localMachines.FindAll(m => !m.Online)) results.Add(Task.Run(() => PingMachine(m.ipAddress, 8000), pingcancel.Token )); await Task.WhenAny(Task.WhenAll(results.ToArray()), Task.Delay(15000)); pingcancel.Cancel(); } catch (Exception ex) { Console.WriteLine(ex); } finally { results.Where(r => r.IsCompleted).ToList() .ForEach(r => //modify the online machines); results.Where(r => r.IsCompleted).ToList().ForEach(r => r.Dispose()); results.Clear(); }La función de ping
static async Task<MachinePingResults> PingMachine(string ipaddress, int timeout) { try { using (Ping ping = new Ping()) { var reply = ping.SendPingAsync(ipaddress, timeout); await Task.WhenAny(Task.Delay(timeout), reply); if (reply.IsCompleted && reply.Result.Status == IPStatus.Success) { return new MachinePingResults(ipaddress, true); } } } catch (Exception ex) { Debug.WriteLine("Error: " + ex.Message); } return new MachinePingResults(ipaddress, false); } Dado que cada Task tiene un retraso para permitir que continúe si el ping se bloquea, no sé cuál sería el problema que está causando que algunos de los resultados de Task<MachinePingResults> nunca finalicen.
¿Cómo puedo asegurarme de que finaliza una Task con .NET Ping ?
Usando .NET 5.0 y los problemas ocurren en máquinas que ejecutan Windows 10 y Windows Server 2012