2016-10-22 2 views
-1

Мне нужно прочитать около 300 файлов, чтобы создать связь со следующим фрагментом кода. Учитывая связь, я должен прочитать их все в памяти.Повышение эффективности (памяти/времени) следующего кода python

with util.open_input_file(f) as f_in: 
    for l in f_in: 
     w = l.split(',') 
     dfm = dk.to_key((idx, i, int(w[0]), int(w[1]))) <-- guaranteed to be unique for each line in file. 
     cands = w[2].split(':') 
     for cand in cands: 
      tmp_data.setdefault(cand, []).append(dfm) 

Тогда мне нужно выписать структуру данных выше, в следующем формате:

k1, v1:v2,v3.... 
k2, v2:v5,v6... 

я использую следующий код:

# Sort/join values. 
    cand2dfm_data = {} 
    for k,v in tmp_data.items(): 
     cand2dfm_data[k] = ':'.join(map(str, sorted(v, key=int))) 
    tmp_data = {} 

    # Write cand2dfm CSV file. 
    with util.open_output_file(cand2dfm_file) as f_out: 
     for k in sorted(cand2dfm_data.keys()): 
      f_out.write('%s,%s\n' % (k, cand2dfm_data[k])) 

Так как я должен обрабатывать значительное количество файлы, я наблюдаю две проблемы:

  1. Память, используемая для хранения tmp_data очень большая. В моем случае использования, обрабатывая 300 файлов, он использует 42 ГБ.

  2. Списание файла CSV занимает много времени. Это потому, что я вызываю write() для каждого элемента() (около 2.2M). Кроме того, выходной поток использует компрессор gzip для экономии места на диске.

В моем используемом случае номера гарантированно будут 32-битными без знака.

Вопрос:

  1. Чтобы добиться снижения памяти, я думаю, что это будет лучше использовать 32-битный Int для хранения данных. Должен ли я использовать ctypes.c_int() для хранения значений в dict() (сейчас они являются строками) или есть лучший способ?

  2. Чтобы ускорить запись, следует ли писать объект StringIO, а затем выгружать его в файл или есть лучший способ?

  3. В качестве альтернативы, может быть, есть лучший способ выполнить вышеуказанную логику, не читая все в памяти?

+3

Если ваш код работает без ошибок, лучшим местом для запроса может быть [codereview.se]. – usr2564301

ответ

2

Немного мыслей.

  1. В настоящее время вы дублируете данные несколько раз в памяти. Вы загружаете его в первый раз в tmp_data, затем копируете все в cand2dfm_data, а затем создаете список ключей по телефону sorted(cand2dfm_data.keys()).

    Чтобы уменьшить использование памяти:

    • Избавиться от tmp_data, анализировать и записывать данные непосредственно в cand2dfm_data

    • Сделать cand2dfm_data список кортежей, а не ДИКТ

    • Используйте cand2dfm_data.sort(...) вместо sorted(cand2dfm_data), чтобы избежать создания нового списка

  2. Чтобы ускорить обработку:

    • Преобразовать ключи в Интс, чтобы улучшить сортировку производительности (это уменьшит использование памяти, а)

    • записи данных на диск на куски, как 100 или 500 или 1000 записей за один раз, это должно улучшить I \ вывода немного

  3. Использование profiler чтобы найти другие узкие места производительности

  4. Если с помощью вышеописанных оптимизаций объем памяти по-прежнему будет слишком большим, рассмотрите возможность использования дискового хранилища для хранения и сортировки временных данных, например. SQLite

+0

Кроме того, если вы работаете с числовыми данными, почему бы не использовать NumPy или такой? Это даст огромный импульс производительности и эффективности работы с памятью. –

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