Самый быстрый способ распознать полностью пустую строку в Python - PullRequest
0 голосов
/ 08 сентября 2018

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

Это мой текущий код:

# options.blocksize = 1024*1024
f, dummy = do_open(dev, 'r')
zeroblock = '\0'*options.blocksize
while True:
    block = f.read(options.blocksize)
    if not block:
        break
    if block == zeroblock:
        csum = "0000"

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

Я также пытался считать NULL вхождений:

# options.blocksize = 1024*1024
f, dummy = do_open(dev, 'r')
zeroblock = '\0'*options.blocksize
while True:
    block = f.read(options.blocksize)
    if not block:
        break
    if block.count('\0') == options.blocksize:
        csum = "0000"

но это даже медленнее, чем первый метод.

Любое предложение о том, как улучшить производительность? Спасибо.

1 Ответ

0 голосов
/ 09 сентября 2018

Вместо if block == zeroblock: попробуйте if not sum(block):. Добавление нулей должно быть очень быстрым.

if not any(block): должен быть примерно таким же быстрым, но для достаточно больших блоков может работать лучше. (Это ярлыки на первом ненулевом.)

Обратите внимание, что не работает с обычными строками Unicode, только строки байтов b'', потому что итераторы строк тестирования возвращают целые числа вместо строк из 1 символа. Это означает, что вы должны open() файл в двоичном режиме с 'rb' вместо просто 'r'.


Python 2 не имеет bytes. Старый тип str, который он использует вместо этого, основывался на байтах, но итератор возвращает строки длины 1 вместо целых чисел, как мы хотим. Таким образом, вы захотите использовать байтовые массивы вместо этого в Python 2. Либо обновите свой Python, либо попробуйте что-нибудь подобное.

from array import array

f, dummy = do_open(dev, 'rb')
while True:
    block = array('B')  # 'B' means bytes. (Actually "unsigned char" in C.)
    try:
        block.fromfile(f, options.blocksize)
    except EOFError:  # Fewer bytes were left than blocksize.
        pass # Remaining bytes were still appended though.
    if not block:
        break
    if not any(block):  # sum() might be faster depending on blocksize.
        csum = "0000"

Вам не нужна часть try / кроме, если вы знаете, что файл делится на блоки равномерно.


Вы также можете попробовать array('L') загрузить данные в виде беззнаковых длин вместо байтов. Вероятно, это будет в четыре раза больше количества итераций, требуемых sum, так как массив будет содержать меньше (больше) элементов, но вам нужно убедиться, что он совпадает с вашим размером блока.

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