Загрузка данных из файлов в память последовательно с#
Может кто подсказать, как на с# грамотно организовать такую штуку:
Есть алгоритм, который использует большие двумерные массивы double данных последовательно. То есть сначала обрабатывает один, потом другой и тд. Результат работы по первому массиву, влияет на работу по второму массиву и тд.
Массивы выгружаются из файлов, файлы выбираются перед началом работы алгоритма.
Я хочу, чтобы файлы загружались в программу (может быть сохранялись в отдельную папку, из которой программа их будет брать (чтобы по всему диску не бегать и искать)), потом по мере работы алгоритма загружались в память (сначала первый массив из файла считался, потом он удалился из памяти и загрузился второй и тд).
У меня именно такой алгоритм, который должен последовательно без разрыва (нет промежуточного результата как бы) сначала использовать один массив данных, потом другой. То есть, есть одно поле класса, в один момент работы алгоритма оно должно хранить один массив, в другой строго определенный момент другой массив. Пока что я сделала так - загружаю все массивы в очередь, потом по мере работы алгоритма удаляю использованный массив из очереди. Но это может использовать много памяти, нужно минимизировать используемую память.
Может кто скинет ссылку на такую информацию, потому что я даже не могу сообразить как этот процесс обозвать, чтобы найти в интернете)
Ответы (1 шт):
Нужна реализация шаблона проектирования Producer/Consumer с ограничением буфера. Под эту задачу легко подходит Channel.
static async Task Main(string[] args)
{
Channel<int> channel = Channel.CreateBounded<int>(2);
Task consumerTask = ConsumeAsync(channel.Reader);
Task producerTask = ProduceAsync(channel.Writer);
await Task.WhenAll(producerTask, consumerTask);
}
static async Task ProduceAsync(ChannelWriter<int> writer)
{
for (int i = 1; i <= 10; i++)
{
await writer.WriteAsync(i);
Console.WriteLine($"> {i}");
}
writer.Complete();
}
static async Task ConsumeAsync(ChannelReader<int> reader)
{
await foreach (int number in reader.ReadAllAsync())
{
Console.WriteLine($"< {number}");
await Task.Delay(1000);
}
}
Здесь я создаю канал передачи данных на буфер размером в 2 ячейки, то есть при попытке положить третий элемент в канал происходит ожидание до тех пор, пока не освободится место в буфере.
Таким образм можно сгладить задержки при чтении данных и отдаче в обработку.
Вывод в консоль, добавлю комментов
> 1
< 1 // здесь первый элемент извлекается сразу, но может и позже, чем появится второй элемент
> 2
> 3 // 2 элемента в буфере, будет ждать, пока не будет извлечен очередной элемент
< 2 // вот он извлекается
> 4 // и сразу же кладется следующий
< 3
> 5
< 4
> 6
< 5
> 7
< 6
> 8
< 7
> 9
< 8
> 10 // последний отправлен в обработку, далее только освобождение буфера
< 9
< 10
То есть регулируя размер буфера, вы сможете регулировать потребление памяти приложением. И да, как вы уже догадались, чтение и запись элементов - две параллельно выполняемых операции.
Почитать подробнее про каналы можно здесь.