2015-01-16 4 views
3

Я довольно новичок в Python и использовал его для скрипта, чтобы открыть папку, фильтровать только файлы, а затем сортировать их по убыванию в зависимости от измененного времени. После этого сценарий запускается в первом файле журнала и ищет любую строку, содержащую слово «сбой», также сохраняя подсчет количества, которое он находит каждый раз. Затем он записывает эту информацию в отдельный файл.Python filter() и sort() слишком долгое время

Проблема, с которой я столкнулась, заключается в том, что этот сценарий занимает 20-30 минут для запуска. Папка содержит 5k + файлов, однако она не должна проходить через все из них. Скрипт хранит в отдельном файле первый файл, который он коснулся в последний раз, когда он запускался, и перестает обрабатывать, как только он снова ударяет файл.

Где я нахожу, что сценарий занимает слишком много времени, это использование встроенных методов filter() и sort(). Может ли кто-нибудь объяснить причины, почему это так медленно, и, возможно, предложить решение?

os.chdir(path) 
files = filter(os.path.isfile, os.listdir(prod_path)) 
files.sort(key = os.path.getmtime, reverse = True) 

for file in files: 
    if file == break_file: 
      break 
    f = open(path + file).readlines() 
    count = 0 #set count of errors to 0 
    dest.write('Upload: ' + file[:file.index(".")] + '\n') #filename, need to truncate off filetype 
    for line in f: #for each line in the the list of lines read from file 
     if line.find('Failure') != -1 and line != f[0]: 
      dest.write(line + '\n') 
      count += 1 
    dest.write('Number of Errors: ' + str(count) + '\n\n') 

if dest.tell() == 0: 
    dest.write('No files to process!') 
dest.close() 
update_file = open(last_run_file, 'w') #last_run_file stores break_file 
update_file.write(str(files[0])) 
print "done"  
+0

Есть именовании для файлов этот каталог? – inspectorG4dget

+1

Фильтр на 5000 строк не должен длиться так долго ... Я получил 26 мс для 5000 файлов с ipython timeit. Можете ли вы опубликовать несколько тестов? – user3467349

+2

Эти файлы хранятся локально или находятся в сетевом ресурсе? Если это последнее, то может объяснить некоторую медлительность, но он все равно не ожидал, что это будет * медленно. – jme

ответ

2

Проблемы, которые я заметил:

  1. , как @ dm03514 упоминается readlines() это плохая идея. Это может привести к высокой замене. Лучше позвонить по телефону for line in open(path + file):
  2. Изменить условия if 'Failure' in line:. Это будет более вещим, и без вызова str.find() может быть быстрее
  3. line != f[0] является проверкой первой линии, я полагаю, так что лучше пропустить его один раз:

    log_file = open(path + file) 
    # read first line 
    log_file.readline() 
    # read rest lines 
    for line in log_file: 
        if 'Failure' in line: 
    
  4. Многопоточности: Python имеет GIL, но он влияет только на операции с ЦП, поэтому вы можете провести разбор каждого файла в отдельном потоке. См threading документация

1

Некоторые незначительные ускорений (там не слишком много деталей в вашем посте, так что это лучшее, что я могу сделать):

import itertools 

os.chdir(path) 
fnames = [fname for fname in os.listdir(prod_path) if os.path.isfile(fname) 
fnames.sort(key=os.path.getmtime, reverse=True) 
firstfile, fnames = itertools.tee(itertools.takewhile(lambda fname: fname != break_file, fnames)) 
firstfile = next(firstfile) 

with open('path/to/dest', 'w') as dest: 
    errord = False 
    for fname in fnames: 
     with open(os.path.join(path, fname)) as infile: 
      numErrors = 0 
      dest.write('Upload: %s\n' %(fname.rsplit('.')[0])) 
      infile.readline() 
      for line in infile: 
       if "Failure" not in line: continue 
       dest.write(line) 
       numErrors += 1 
      dest.write('Number of Errors: %d\n\n' %numErrors) 

    if not errord: 
     dest.write('No files to process!') 

with open(last_run_file, 'w') as update_file: 
    update_file.write(firstfile) 
Смежные вопросы