Стоит задача сделать программу мониторинга железок по SNMP(не спрашивайте зачем, сам в шоке) Планирую использовать c# и библиотеку SNMP lex. Мониториться могут много железок, сотня, а то и больше. Каждая железка имеет кучу параметров для мониторинга.
Хотел сделать так. Мониторинг каждого параметра запускается в отдельном Task в бесконечном цикле и параметр опрашивается каждые 5 секунд.
Выглядит это ужасно, поскольку 100 железок на 20 параметров, итого 2000 тасков с бесконечным циклом.
Посоветуйте, как лучше решить задачу?
Предположим, что вы будете запрашивать информацию асинхронно.
Например, так
static Random r = new Random();
public Task<int> GetDeviceParameter(int deviceId, int parameterId)
{
return Task.Delay(1000).ContinueWith(t=>r.Next());
}
Я предположил, что запрос занимает 1 секунду. Теперь запросим 20 параметров по конкретному девайсу
public Task<int[]> ReadDeviceParameters(int decviceId)
{
var tasks = new Task<int>[20];
for(var i=0; i<20; i++)
{
tasks[i] = GetDeviceParameter(decviceId, i);
}
return Task.WhenAll(tasks);
}
Все вроде просто. Запросим это для 100 девайсов
public Task<int[][]> ReadParameters()
{
var tasks = new Task<int[]>[100];
for (var i = 0; i < 100; i++)
{
tasks[i] = ReadDeviceParameters(i);
}
return Task.WhenAll(tasks);
}
Теперь, как оранизовать цикл? Нам, наверное, надо иметь токен отмены для цикла и засекать время, чтобы цикл запускался каждые 5 секунд, но после отработки предыдущих запросов.
public async Task ReadParametersLoop(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
var start = DateTime.UtcNow;
Console.WriteLine($"Starting read at {start:mm:ss}");
await ReadParameters();
var end = DateTime.UtcNow;
var diff = end - start;
var delay = (int)Math.Min(5000, 5000 - diff.TotalMilliseconds);
Console.WriteLine($"Reading ens at {end:mm:ss}, took {diff}, delay for {delay}");
if (delay > 0)
await Task.Delay(delay);
}
}
Запускаю это в консоли на 15 секунд
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(15));
await ReadParametersLoop(cts.Token);
Получаю результат
Starting read at 29:56
Reading ens at 29:57, took 00:00:01.0061006, delay for 3993
Starting read at 30:01
Reading ens at 30:02, took 00:00:01.0161016, delay for 3983
Starting read at 30:06
Reading ens at 30:07, took 00:00:01.0161016, delay for 3983
Таким образом, если запросы отрабатывают меньше, чем за 5 секунд (в сумме), то они стабильно запрашиваются каждые 5 секунд.
Вы можете воспользоваться реактивными расширениями System.Reactive
Небольшой пример как работать с мониторингом параметров используя IObservable
Вместо Dictionary
с параметрами, можно создать отдельный класс.
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"Start: {DateTime.Now}");
var parameters = Enumerable.Range(0, 100).Select(x => $"Parameter {x}").ToArray();
var devices = Enumerable.Range(0, 20).Select(x => $"Device {x}").ToArray();
foreach (var device in devices)
{
var monitor = Observable.FromAsync(() => GetParametersAsync(parameters))
.Delay(TimeSpan.FromSeconds(5))
.Repeat();
monitor.Subscribe(x => HandleParameters(device, x));
}
Console.ReadLine();
}
/// <summary>
/// Пример обработки параметров
/// </summary>
private static void HandleParameters(string device, Dictionary<string, string> parameters)
{
foreach (var parameter in parameters)
{
Console.WriteLine($"{device} {parameter.Key}: {parameter.Value}");
}
Console.WriteLine();
}
private static async Task<Dictionary<string, string>> GetParametersAsync(string[] parameterIds)
{
var parameters = parameterIds.Select(parameterId => new { Id = parameterId, Task = GetParameterAsync(parameterId) }).ToList();
var tasks = parameters.Select(x => x.Task).ToArray();
await Task.WhenAll(tasks);
var results = new Dictionary<string, string>();
foreach (var parameter in parameters)
{
results.Add(parameter.Id, parameter.Task.Result);
}
return results;
}
/// <summary>
/// Эмуляция получения данных
/// </summary>
public static async Task<string> GetParameterAsync(string parameterId)
{
await Task.Delay(3000);
return DateTime.Now.ToString();
}
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
Изучаю тему IoC и DIВсё вроде понял зачем как и почему пока не дошел до IoC контейнера Unity
Например, у меня есть txt файл на удалённом компьютере в его открытой сетевой папкеНужно локально считать этот файл
Всех приветствую, вопрос такой, изучаю этот парсер, вот страница, которую я хочу разобратьВот мой код