Есть ли какой-либо выигрыш в эффективности при записи случая 99% сначала в цикле if? - PullRequest
0 голосов
/ 02 июля 2019

У меня есть некоторый код Python, который оценивает файл строка за строкой, как это:

def evaluate_file():
  firstline = True
  for line in lines:
    if firstline:
      # do something with the first line
      firstline = False
    else
      # do something else

99% времени, на что смотрят, это , а не первая строка.Есть ли какое-либо улучшение эффективности для написания первого случая 99%, то есть первого оператора if, равного if !firstline?

Ответы [ 3 ]

1 голос
/ 02 июля 2019

Разница будет незначительной, если ваше 1% -ое условие будет просто "первой строкой". Что могло бы сэкономить время, так это выполнить 1% за пределами цикла, а затем безоговорочно выполнить цикл для последующих элементов. Это сэкономит 99% бесполезного тестирования для условия первой строки и, что более важно, улучшит удобочитаемость вашего кода (хотя бы за счет уменьшения уровней отступа).

Использование итератора - эффективный способ сделать это разделение. Например:

iLines =iter(lines)
for line in iLines:
    # do something with the first line
    break 
for line in iLines:
    # do something else with other lines

Это будет работать со списками и с источниками, которые не могут быть проиндексированы или разрезаны. Это также учитывает более сложные условия «первой части», которые могут потребовать пропустить более одного начального элемента.

Если код, который нужно выполнить для первой строки, является «дополнением» к общему коду для всех строк, может быть проще использовать перечисление вместо переменной-флага (хотя это немного медленнее):

for i,line in enumerate(lines):
    if i==0:
       # do something special for the first line
    # common code for all lines 

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

1 голос
/ 02 июля 2019

Написал быстрый маленький тест, возможно, не идеальный, но здесь идет.

Результаты на основе 1 109 890 строк данных и 100 выполнений:

  • ifTest: 0,0472489972114563 секунд
  • arrayTest: 0.06530603981018067 секунд
  • flipIfTest: 0,04617302393913269 секунд

Выигрыш в производительности, который вы получите, предложив изменение, довольно небольшой, но оно того стоит.

Несмотря на то, что arrayTest был самым медленным, я бы все же предпочел его, так как он кажется немного более интуитивным.

Код:

import time

def ifTest(lines): 
    count = 0
    firstline = True
    for line in lines:
        if firstline:
            firstline = False
        else:
            count = count + 1
    return count

def arrayTest(lines):
    count = 0
    firstline = lines[0]
    for line in lines[1:]:
        count = count + 1
    return count

def flipIfTest(lines):
    count = 0
    firstline = True
    for line in lines:
        if not firstline:
            count = count + 1
        else:
            firstline = False
    return count

f = open("data.txt", "r")
lines = f.read().splitlines()

runs = 100

avg = 0
for i in range(0,runs):
    start = time.time()
    res = ifTest(lines)
    end = time.time()
    print("Lines Read: {}, Time: {}".format(res, end - start))
    avg = avg + (end - start)
avg = avg / runs
print("ifTest: {}".format(avg))

avg = 0
for i in range(0,runs):
    start = time.time()
    res = arrayTest(lines)
    end = time.time()
    print("Lines Read: {}, Time: {}".format(res, end - start))
    avg = avg + (end - start)
avg = avg / runs
print("arrayTest: {}".format(avg))

avg = 0
for i in range(0,runs):
    start = time.time()
    res = flipIfTest(lines)
    end = time.time()
    print("Lines Read: {}, Time: {}".format(res, end - start))
    avg = avg + (end - start)
avg = avg / runs
print("flipIfTest: {}".format(avg))
1 голос
/ 02 июля 2019

Если в сценарии использования есть что-то еще (что потребовало бы обновления вопроса с помощью [mcve]), зачем использовать условную для определения «первой» строки, когда вы можете просто нарезать lines и делать то, что вам нужно с помощью сначала, а потом еще что-нибудь с остальными?

def evaluate_file():
  # evaluate the first line:
  # do something with ``lines[0]``

  for line in lines[1:]
      # do some
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...