2013-02-22 3 views
3

Это мой второй день работы в Python. Я некоторое время работал над этим на C++, но решил попробовать Python. Моя программа работает так, как ожидалось. Однако, когда я обрабатываю один файл за один раз без цикла glob, он занимает около получаса за файл. Когда я включаю glob, цикл занимает около 12 часов для обработки 8 файлов.Цитирование через большие файлы занимает часы в Python

Мой вопрос в том, есть ли что-нибудь в моей программе, которое определенно замедляет его? есть ли что-нибудь, что я должен делать, чтобы сделать это быстрее?

У меня есть папка с большими файлами. Например

file1.txt (6gb) file2.txt (5.5gb) file3.txt (6gb)

Если это помогает, каждая строка данных начинается с символа, который говорит мне, как все остальные символы отформатированы, поэтому у меня есть все утверждения if elif. Линия данных будет выглядеть следующим образом: T35201 M352 RZNGA AC

Я пытаюсь читать каждый файл, сделать некоторый синтаксический анализ с помощью шпагата, а затем сохраните файл.

Компьютер имеет 32 ГБ оперативной памяти, поэтому мой метод состоит в том, чтобы читать каждый файл в ram, а затем прокручивать файл, а затем сохранять, освобождая RAM для следующего файла.

Я включил файл, чтобы вы могли видеть методы, которые я использую. Я использую оператор if elif, который использует около 10 различных команд elif. Я пробовал словарь, но я не мог понять это, чтобы спасти свою жизнь.

Любые ответы были бы полезными.

import csv 
import glob 

for filename in glob.glob("/media/3tb/5may/*.txt"): 
    f = open(filename,'r') 
    c = csv.writer(open(filename + '.csv','wb')) 

    second=0 
    mill=0 
    for line in f.readlines(): 
     #print line 
     event=0 
     ticker=0 
     marketCategory=0 
     variable = line[0:1]  

     if variable is 'T': 
      second = line[1:6] 
      mill=0 
     else: 
      second = second 

     if variable is 'R': 
      ticker = line[1:7] 
      marketCategory = line[7:8] 
     elif variable is ... 
     elif variable is ... 
     elif ... 
     elif ... 
     elif ... 
     elif ... 
     elif   

     if variable (!= 'T') and (!= 'M') 
      c.writerow([second,mill,event ....]) 
    f.close() 

UPDATE Каждый из операторов Элиф почти идентичны. Единственными частями, которые меняются, являются способы разделить линии. Вот два заявления Элиф (Есть 13 общая, и почти все они идентичны за то, как они расщепляются, за исключением.)

elif variable is 'C': 
    order = line[1:10] 
    Shares = line[10:16] 
    match = line[16:25] 
    printable = line[25:26] 
    price = line[26:36] 
    elif variable is 'P': 
    ticker = line[17:23] 
    order = line[1:10] 
    buy = line[10:11] 
    shares = line[11:17] 
    price = line[23:33] 
    match = line[33:42] 

UPDATE2 Я побежал код, используя for file in f два различных раза. В первый раз я запустил один файл безfor filename in glob.glob("/media/3tb/file.txt"): и потребовалось около 30 минут, вручную закодировав путь к файлу для одного файла.

Я запустил его снова сfor filename in glob.glob("/media/3tb/*file.txt") и потребовался час только для одного файла в папке. Добавляет ли код glob столько времени?

+4

Было бы просто изменить 'для строки в f.readlines():' to 'для строки в f:'. Таким образом, вы не читаете весь файл в памяти сразу, а скорее по одной строке за раз. Также 'variable = line [0: 1]' совпадает с 'variable = line [0]', что на самом деле не влияет на скорость. – 2013-02-22 14:05:03

+0

use 'line [0] == 'T'' вместо' variable is' T''. Последний может потерпеть неудачу ('is' проверяет идентичность объекта и может быть более одного объекта' T '). – jfs

+0

какую версию python вы используете? Вы также можете установить буферизацию и загрузить файл с помощью chuncks: buffersize = 50000000, buffer = infile.read (buffersize), в то время как len (buffer): здесь здесь – Drewdin

ответ

9

Здесь:

for line in f.readlines(): 

Вы должны просто сделать это:

for line in f: 

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

+0

Я пробовал делать это для одного файла, и скорость примерно такая же, 30 минут. С Python нет ли узких мест ввода-вывода, если я не буду читать все это в памяти? Я прокручу пару файлов и буду обновлять их с помощью вашего метода. Еще раз спасибо. – BrianR

+0

Вы можете проверить, потребляет ли ваша программа 100% -ный процессор или где-нибудь рядом с ним, а если нет, вероятно, он ограничен вводом-выводом. Если вы читаете одни и те же файлы ввода снова и снова (в последующих прогонах программы), вам следует подумать о написании переводчика, который читает CSV и пишет NumPy «ndarray», затем последующие прогоны могут просто загружать массив и работать с этим , что должно быть несколько быстрее. В конце концов, однако, вам нужно решить, какие критерии производительности у вас есть, и если вам нужно, чтобы это было очень быстро, вам нужно выбрать другой язык для «горячей» части кода, по крайней мере. –

2

Всякий раз, когда вы спрашиваете, «какая часть этого замедляет все это?» ответ «профиль».«Отличное описание того, как это сделать в документации Python по адресу The Python Profilers.Кроме того, как указывает Джон Звинк, вы загружаете слишком много в память сразу и должны загружать только одну строку за раз (объекты файлов« итерируются » "в Python).

Лично я предпочитаю, что Perl называет„диспетчерская стол“с огромным if..elif...elif уродства. This webpage описывает Pythonic способ сделать это. Это словарь ключей к функциям, которые не работают во всех но для простого if x==2:...elif x==3... (т. е. включение значения одной переменной) он отлично работает.

1

Используйте итерируемый (используя выход), чтобы «буферизировать» больше строк в памяти, чем только одну строку за раз, но НЕ всего файла за один раз.

def readManyLines(fObj,num=1000): 
    lines = fObj.readlines(num) 
    for line in lines: 
    yield line 

f = open(filename,'r') 
for line in readManyLines(f): 
    process(line) 
+0

Здесь num - количество прочитанных байтов. Он попытается прочитать, что многие байты затем читают больше байтов, чтобы сделать полную строку. file.readlines (num) всегда будет возвращать полные строки и не останавливаться после num байтов. – g19fanatic

0

Не уверен, что это вообще помогает, но попробуйте использовать это вместо glob.glob, чтобы исключить, что это проблема. Я на окнах, поэтому я не могу быть на 100% уверенным, что это работает под Unix, но я не понимаю, почему это не так.

import re 
import os 
import csv 

def find_text_files(root): 
    """Find .txt files under a given directory""" 
    foundFiles = [] 
    for dirpath, dirnames, filenames in os.walk(root): 
     for file in filenames: 
      txt = re.compile(r'txt$',re.I,).search(file) 
      if txt: 
       foundFiles.append(os.path.join(dirpath,file)) 
    return foundFiles 

txtfiles = find_text_files('d:\files') #replace the path with yours 

for filename in txtfiles: 
    f = open(filename,'r') 
    c = csv.writer(open(filename + '.csv','wb'))