Медленный питон файл I: O;Руби работает лучше, чем это;Есть неправильный язык? - PullRequest
0 голосов
/ 22 марта 2011

Пожалуйста, сообщите - я собираюсь использовать это в качестве учебного пункта.Я новичок.

Я разделяю файл размером 25 МБ на несколько файлов меньшего размера.

Добрый гуру дал мне скрипт на Ruby.Работает прекрасно быстро.Итак, чтобы учиться, я подражал этому скрипту на python.Это бежит как трехногая кошка (медленно).Интересно, может кто-нибудь сказать мне, почему?

Мой скрипт на питоне

    ##split a file into smaller files
###########################################
def splitlines (file) :
        fileNo=0001
        outFile=open("C:\\Users\\dunner7\\Desktop\\Textomics\\Media\\LexisNexus\\ele\\newdocs\%s.txt" % fileNo, 'a') ## open file to append 
        fh = open(file, "r") ## open the file for reading
        mylines = fh.readlines() ### read in lines
        for line in mylines: ## for each line
                        if re.search("Copyright ", line): # if the line is equal to the regex
                            outFile.close()  ##  close the file
                            fileNo +=1  #and add one to the filename, starting to read lines in again
                        else: # otherwise
                            outFile=open("C:\\Users\\dunner7\\Desktop\\Textomics\\Media\\LexisNexus\\ele\\newdocs\%s.txt" % fileNo, 'a') ## open file to append 
                            outFile.write(line)          ## then append it to the open outFile          
        fh.close()

Скрипт гуру на Ruby 1.9

g=0001
f=File.open(g.to_s + ".txt","w")
open("corpus1.txt").each do |line|
  if line[/\d+ of \d+ DOCUMENTS/]
    f.close
    f=File.open(g.to_s + ".txt","w")
    g+=1
  end
  f.print line
end

Ответы [ 4 ]

6 голосов
/ 22 марта 2011

Существует много причин, по которым ваш скрипт работает медленно - основная причина в том, что вы открываете выходной файл почти для каждой строки, которую вы пишете.Поскольку старый файл неявно закрывается при открытии нового (из-за сборки мусора в Python), буфер записи сбрасывается для каждой записываемой строки, что довольно дорого.

Очищенная и исправленная версияваш сценарий будет

def file_generator():
    file_no = 1
    while True:
        f = open(r"C:\Users\dunner7\Desktop\Textomics\Media"
                 r"\LexisNexus\ele\newdocs\%s.txt" % file_no, 'a')
        yield f
        f.close()
        file_no += 1

def splitlines(filename):
    files = file_generator()
    out_file = next(files)
    with open(filename) as in_file:
        for line in in_file:
            if "Copyright " in line:
                out_file = next(files)
            out_file.write(line)
        out_file.close()
2 голосов
/ 22 марта 2011

Я думаю, причина того, что ваш скрипт такой медленный, в том, что вы открываете новый дескриптор файла для каждой строки. Если вы посмотрите на скрипт ruby ​​вашего гуру, он закроет и откроет выходной файл, только если ваш разделитель совпадает.

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

Еще одно изменение, которое я бы предложил, это изменить

fh = open(file, "r") ## open the file for reading
mylines = fh.readlines() ### read in lines
for line in mylines: ## for each line

до

fh = open(file, "r")
for line in fh:

С этим изменением вы не читаете весь файл в память, а только блок за блоком. Хотя это не имеет значения для файла размером 25 МБ, это повредит вам большими файлами и является хорошей практикой (и меньшим количеством кода;)).

0 голосов
/ 22 марта 2011

Rosser,

Не использовать имена встроенных объектов в качестве идентификаторов в коде (файл, разделенные линии)

Следующий код учитывает влияние вашего собственного кода: out_file закрывается без строки, содержащей «Copyright», которая представляет собой сигнал закрытия

Использование функции writelines () предназначено для обеспечения более быстрого выполнения, чем при повторении out_file.write(line)

Блок if li: предназначен для запуска закрытия out_file , если последняя строка прочитанного файла не содержит «Copyright»

def splitfile(filename, wordstop, destrep, file_no = 1, li = []):
    with open(filename) as in_file:
        for line in in_file:
            if wordstop in line:
                with open(destrep+str(file_no)+'.txt','w') as f:
                    f.writelines(li)
                file_no += 1
                li = []
            else:
                li.append(line)
        if li:
            with open(destrep+str(file_no)+'.txt','w') as f:
                f.writelines(li)
0 голосов
/ 22 марта 2011

Код Python может быть медленным из-за регулярных выражений, а не из-за ввода-вывода. Попробуйте

def splitlines (file) :
  fileNo=0001
  outFile=open("newdocs/%s.txt" % fileNo, 'a') ## open file to append 
  reg = re.compile("Copyright ")
  for line in open(file, "r"): 
    if reg.search("Copyright ", line): # if the line is equal to the regex
      outFile.close()  ##  close the file
      outFile=open("newdocs%s.txt" % fileNo, 'a') ## open file to append 
      fileNo +=1  #and add one to the filename, starting to read lines in again

    outFile.write(line)          ## then append it to the open outFile          

Несколько примечаний

  • Всегда используйте / вместо \ дляимя пути
  • Если регулярное выражение используется повторно, скомпилируйте его
  • Вам нужен re.search?или re.match?

ОБНОВЛЕНИЕ:

  • @ Ред.S: точка взята
  • @ Уинстон Эверт: код обновлен, чтобы быть ближе к исходному коду Ruby
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...