Dart занимает слишком много оперативной памяти при генерации случайных чисел и добавлении их в файл

#dart #file-io #dart-io

Вопрос:

Я занимаюсь проектом, который включает в себя генерацию 1 миллиарда случайных чисел 0/1 и хранение их в файле. Это мой код:

 import 'dart:io';
import 'dart:math';

final int COUNT = 1000000000;
final Random randomizer = new Random();
final File file = new File('./dart/dart.txt');

void main() {
  if (file.existsSync()) {
    file.deleteSync();
  }
  file.createSync();
  
  DateTime before = new DateTime.now();
  IOSink sink = file.openWrite(mode: FileMode.append);

  for (int i = 0; i < COUNT; i  ) {
    sink.write(nextNumber().toString());
  }
  sink.close();

  DateTime after = new DateTime.now();
  print(after.millisecondsSinceEpoch - before.millisecondsSinceEpoch);
}

int nextNumber() {
  return randomizer.nextInt(2);
}
 

Это прекрасно работает COUNT=10000 , если для генерации 10000 случайных чисел требуется дюжина миллисекунд. Однако, когда я собрал COUNT 1 миллиард, это заняло около 25 ГБ моей оперативной памяти и продолжалось более 40 минут без остановок. Мне пришлось убить процесс, вместо того чтобы позволить ему продолжать работать.

Как я могу это исправить?

P.S. Я не могу изменить язык программирования, так как использование разных языков программирования для генерации таких чисел является одним из аспектов моего проекта. Я также использую C , Java, Javascript, PS, Python и т.д. Для создания таких больших данных, и ни один из них не сталкивался с этой проблемой. Конечный файл, в котором хранятся данные, составляет менее 1 ГБ.

Комментарии:

1. Обратите внимание, что вы измеряете время для вычисления COUNT случайных чисел, но не время для их записи на диск (поскольку вы пренебрегаете этим await sink.flush(); await sink.close(); в первую очередь). Поэтому кажущееся затраченное время не будет масштабироваться так, как ожидалось. Я также подозреваю, что IOSink это не приводит к автоматической очистке буфера, когда он становится слишком полным, поэтому вы в конечном итоге буферизуете все COUNT значения. Возможно, вам следует await sink.flush(); периодически звонить (например, каждые 10000 итераций), что, надеюсь, исправит использование оперативной памяти (и, возможно, поможет с продолжительностью, если использование оперативной памяти вызвало подкачку).

2. Я понял, что дело не в том , что IOSink буфер не очищается автоматически (и вы можете наблюдать, что dart.txt он растет без явной очистки), а в том, что без случайного await sink.flush(); цикла ваши данные генерируются намного быстрее, чем они могут быть записаны на диск, поэтому IOSink в конечном итоге буферизуются почти все.