2014-09-16 3 views
0

Мне нужно записать большое количество несортированных данных (50000000 номеров) в файл. Во время выполнения я получаю OutOfMemoryException. Как это исправить?Исключение из памяти, пытаясь записать большой объем данных в файл

private void backgroundWorkerGenNum_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int numLimit = 50000000; 
    Random randomize = new Random(); 
    List<string> strNums = new List<string>(); 

    var array = Enumerable.Range(1, numLimit).ToArray(); 
    array = array.OrderBy(n => Guid.NewGuid()).ToArray(); 
    StreamWriter file = new StreamWriter("numbers.txt"); 
    int i = 0; 
    foreach(int element in array) 
    { 
     file.WriteLine(element); 
     ++i; 
     backgroundWorkerGenNum.ReportProgress(i); 
    } 
} 
+0

Покажите полную трассировку стека ошибок, пожалуйста. –

+0

Post ReportProgress также – RyPope

+3

Также: 'StreamWriter' реализует' IDisposable', и поэтому его время жизни должно быть обернуто в конструкцию 'using', поэтому оно детерминировано. –

ответ

4

Прежде всего, вы можете просто перетасовать свой массив так:

public static class ArrayExtender 
{ 
    public static void Shuffle<T>(this T[] a) 
    { 
     Random rand = new Random(); 
     for (int i = a.Length - 1; i > 0; i--) 
     { 
      int j = rand.Next(0, i + 1); 
      T tmp = a[i]; 
      a[i] = a[j]; 
      a[j] = tmp; 
     } 
    } 
} 

хорошо, теперь мы можем генерировать рандомизированное данные:

private void backgroundWorkerGenNum_DoWork(object sender, DoWorkEventArgs e) 
    { 
     int numLimit = 50000000; 

     var array = Enumerable.Range(1, numLimit).ToArray(); 
     array.Shuffle(); 
     int i = 0; 
     using(StreamWriter file = new StreamWriter("numbers.txt")) 
      foreach (int element in array) 
      { 
       file.WriteLine(element); 
       ++i; 
       backgroundWorkerGenNum.ReportProgress(i); 
      } 
    } 
+2

Если вы укажете исправленную версию кода, вы также должны исправить неизолированный StreamWriter. –

+0

Я бы, вероятно, также переместил генератор случайных чисел из самого метода (класс static 'static readonly'), а затем этот метод может стать еще более общим и свободно с сигнатурой' public static IEnumerable Shuffle (этот IList a) ' –

+0

@ScottChamberlain извините, я выбрал код TS без редактирования :(Done. –

1

Это очень неэффективный способ рандомизации набор чисел:

array = array.OrderBy(n => Guid.NewGuid()).ToArray(); 

Каждый новый Guid вы генерируете требует 16 Byes + несколько байт накладных расходов для магазина.

У вас есть номера 5 * 10^7, которые вы производите, злоупотребляя методом OrderBy.

OrderBy внутренне попытается сортировать вашу коллекцию, используя предоставленные вами ключи, которые требуют от нее выделить память для данных и ключей. Предполагая, что заказ хранит сгенерированный ключ вместе с каждым элементом, для этого потребуется более 1 ГБ места в памяти.

+1

Не только это неэффективно, на него нельзя полагаться фактически на * работу *, поскольку идентификаторы GUID гарантируются только * уникальным *, а не * случайным *. – Servy

+1

@DeeMac Ну, это то, что он утверждает. В качестве детализации реализации это на самом деле ложь в том, что столкновения технически возможны, хотя это и невозможно в практическом смысле. Вы можете полагаться на уникальный идентификатор GUID, поскольку это то, что он построил. – Servy

+1

'OrderBy' вычисляет все ключи заранее; он не вызывает селектор несколько раз для каждого элемента. – Servy

1

следует использовать метод воспроизведения в случайном порядке, как этот

private void Shuffle(int[] data) 
{ 
    var random = new Random(); 

    int n = data.Length; 
    for (int i = 0; i < n; i++) 
    { 
     int idx = random.Next(i, n); 

     int x = data[i]; 
     data[i] = data[idx]; 
     data[idx] = x; 
    } 
} 

вместо array.OrderBy(n => Guid.NewGuid()).ToArray()

Смежные вопросы