Зачем открывать и повторять обработку файлов в два раза быстрее в Python 2 по сравнению с Python 3? - PullRequest
0 голосов
/ 28 сентября 2018

Я не могу понять, почему анализировать этот файл в Python 2.7 намного быстрее, чем в Python 3.6.Я нашел этот шаблон независимо от MacOS и Arch-Linux.Могут ли другие повторить это?Любое объяснение?

Предупреждение: фрагмент кода записывает файл ~ 2 ГБ

Время:

$ python2 test.py 
5.01580309868
$ python3 test.py 
10.664075019994925

Код для test.py:

import os

SEQ_LINE = 'ATCGN'* 80 + '\n'

if not os.path.isfile('many_medium.fa'):
    with open('many_medium.fa', 'w') as out_f:
        for i in range(1000000):
            out_f.write('>{}\n'.format(i))
            for _ in range(5):
                out_f.write(SEQ_LINE)

from timeit import timeit

def f():
    with open('many_medium.fa') as f:
        for line in f:
            pass

print(timeit('f()', setup='from __main__ import f', number=5))

Ответы [ 2 ]

0 голосов
/ 18 ноября 2018

Поскольку в Python 2 стандартный вызов open() создает гораздо более простой файловый объект, чем вызов Python 3 open().Вызов Python 3 open - это то же самое, что и io.open(), и тот же фреймворк доступен на Python 2 .

Чтобы сделать это честное сравнение, вам нужно добавить следующую строку в начало вашего теста:

from io import open

С этим изменением время в Python 2 увеличится с 5,5 секунд до 37 секунд.По сравнению с этим показателем, 11 секунд, которые Python 3 берет на мою систему для запуска теста, действительно намного, намного быстрее .

Так что же здесь происходит?Библиотека io предлагает гораздо больше функциональных возможностей, чем старый объект Python 2 file:

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

Эта дополнительная функциональность достигается за счет производительности.

Но ваш тест Python 2 читает строки байтов , переводы строки всегда переводятся в \n, а файловый объект, с которым работает код, довольно близок к предоставленному OS файловому примитиву,с все минусы .В Python 3 обычно требуется обрабатывать данные из файлов в виде текста, поэтому при открытии файла в текстовом режиме вы получаете файловый объект, который декодирует двоичные данные в объекты Unicode str.

Итак, как вы можете сделатьдела идут быстрее на Python 3?Это зависит от вашего конкретного варианта использования, но у вас есть несколько вариантов:

  • Для файлов в текстовом режиме отключите универсальную обработку новой строки, особенно при обработке файла, в котором используются окончания строк, которые отличаются от стандарта платформы.Установите для параметра newline ожидаемую последовательность символов новой строки, например \n.Двоичный режим поддерживает только \n в качестве разделителя строк.
  • Обрабатывает файл как двоичные данные и не декодирует до str.В качестве альтернативы, декодирование в Latin-1, прямое сопоставление один на один из байта в кодовую точку.Это вариант, когда ваши данные также только для ASCII, где Latin-1 пропускает проверку ошибок байтов в диапазоне 0-127, а не 0-255.

При использовании mode='rb', Python 3 может легко соответствовать временам Python 2, тест занимает в моей системе всего 5,05 секунды, используя Python 3.7.

Использование latin-1 в качестве кодека по сравнению с UTF-8 (обычное значение по умолчанию)только небольшая разница;UTF-8 может быть очень эффективно декодирован.Но это может иметь значение для других кодеков.Обычно вы хотите явно установить параметр encoding и не полагаться на используемую по умолчанию кодировку .

0 голосов
/ 14 ноября 2018

Провел некоторое исследование и наткнулся на эту статью Нельсона Минара, которая объясняет разницу между чтением файлов python2 и python3.

  • Python 3примерно в 1.7 раза медленнее читает байты построчно, чем Python 2

  • В Python 2 чтение строк с Unicode выполняется очень медленно.Примерно в 7 раз медленнее, чем чтение Юникода одновременно.И строки Unicode в 70 раз медленнее, чем строки байтов!

  • В Python 3 чтение строк с Unicode происходит довольно быстро.Примерно так же быстро, как и чтение файла одновременно.Но только если вы используете встроенные открытые, а не кодеки.

  • В Python 3 кодеки действительно медленно читают построчно.Избегайте.

И продолжает говорить:

Декодирование Python 3 UTF-8 значительно быстрее, чем Python 2. И, вероятно, лучше придерживатьсясо стоковым вызовом open () в Py3, а не с кодеками.В некоторых случаях это может быть медленнее, но рекомендуемый вариант идет дальше, и разница невелика.

Согласно SO-ответу , что @ user2357112 связанный:

Когда вы открываете файл в Python в текстовом режиме (по умолчанию), он использует то, что он называет «универсальными символами новой строки» (введен в PEP 278, но несколько изменился позже с выходомПитон 3).Универсальные символы новой строки означают, что независимо от того, какие символы новой строки используются в файле, в Python вы увидите только \ n.Таким образом, файл, содержащий foo \ nbar, будет выглядеть так же, как и файл, содержащий foo \ r \ nbar или foo \ rbar (поскольку \ n, \ r \ n и \ r - это соглашения об окончании строк, используемые в некоторых операционных системах в определенное время).

Решение, упомянутое в этом ответе, состоит в том, чтобы открыть файл в байтовом режиме, чтобы избежать преобразования:

open('many_medium.fa', "r+b")

Мои тесты показали огромную разницу в скорости, но python2все еще казалось немного быстрее.Кажется, нет способа избежать этого, так как он обрабатывается интерпретатором python.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...