LINUX.ORG.RU

python3, что лучше — 1000 раз if или 2 раза перебор range?

 


2

1

1 вариант:

#!/usr/bin/python3
aa=True
for i in range(100000):
    a=i
    if aa:
        zz=i

2 вариант:

#!/usr/bin/python3
aa=True
for i in range(100000):
    a=i

if aa:
    for i in range(100000):
        zz=i

Что лучше? При условии, что в реальном скрипте не range, а список из 1-300 элементов.

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

★★★

python3, что лучше — 1000 раз if или 2 раза перебор range?

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

Очевидно, второй вариант получше первого.

Deleted
()

Так правильно делать или нет?

vodka@vodka-PC:/tmp$ sudo perf stat ./var1.py 

 Performance counter stats for './var1.py':

         50,473740      task-clock (msec)         #    0,986 CPUs utilized          
                 4      context-switches          #    0,079 K/sec                  
                 0      cpu-migrations            #    0,000 K/sec                  
             1 100      page-faults               #    0,022 M/sec                  
        85 093 875      cycles                    #    1,686 GHz                    
       170 501 441      instructions              #    2,00  insn per cycle         
        34 842 930      branches                  #  690,318 M/sec                  
           654 226      branch-misses             #    1,88% of all branches        

       0,051192785 seconds time elapsed

       0,035310000 seconds user
       0,015693000 seconds sys


vodka@vodka-PC:/tmp$ sudo perf stat ./var2.py 

 Performance counter stats for './var2.py':

         30,877101      task-clock (msec)         #    0,992 CPUs utilized          
                 1      context-switches          #    0,032 K/sec                  
                 0      cpu-migrations            #    0,000 K/sec                  
             1 102      page-faults               #    0,036 M/sec                  
        95 083 029      cycles                    #    3,079 GHz                    
       197 871 550      instructions              #    2,08  insn per cycle         
        40 542 764      branches                  # 1313,037 M/sec                  
           661 730      branch-misses             #    1,63% of all branches        

       0,031137923 seconds time elapsed

       0,022242000 seconds user
       0,008896000 seconds sys

Видно, что первый код выполняется быстрее. Это так?

iljuase ★★★
() автор топика
Ответ на: комментарий от Deleted

Реальный код немного иной.

Вариант 1:

    for key, value in sorted(content_updates_pkgs.items()):
        if kernel_update == "no":
            if str(key).startswith("kernel") == True or str(key).startswith("linux-image") == True:
                kernel_update = "yes"
                format_kernel = format['format_red']
                reboot_require = "yes"
                format_reboot = format['format_red']
        sheet.write(counter + 2, 0, key, format['format_border'])
        try:
            current_version=content_all_pkgs[key]
        except KeyError:
            current_version="new packages (will be installed as dependency)"
        for coun, content in enumerate((key, current_version, value)):
            sheet.write(counter+2, coun, content, format['format_border'])
        if args.csv:
            csv_writer.writerow((key, current_version, value))
        counter += 1

Вариант 2:

    for key, value in sorted(content_updates_pkgs.items()):
        if kernel_update == "no":
            if str(key).startswith("kernel") == True or str(key).startswith("linux-image") == True:
                kernel_update = "yes"
                format_kernel = format['format_red']
                reboot_require = "yes"
                format_reboot = format['format_red']
        sheet.write(counter + 2, 0, key, format['format_border'])
        try:
            current_version=content_all_pkgs[key]
        except KeyError:
            current_version="new packages (will be installed as dependency)"
        for coun, content in enumerate((key, current_version, value)):
            sheet.write(counter+2, coun, content, format['format_border'])
        counter += 1

if args.csv:
    for key, value in sorted(content_updates_pkgs.items()):
        try:
            current_version=content_all_pkgs[key]
        except KeyError:
            current_version="new packages (will be installed as dependency)"
        csv_writer.writerow((key, current_version, value))

iljuase ★★★
() автор топика

А я думал на скриптопараше пишут так чтобы читаемее/короче было, а для пирформанса идут в с++шку.

anonymous
()

Возьми да сравни. Если хочешь позаботиться и о додиках, порежь процессор хотя бы на предмет частоты до 200 ккгц и сравни 2.7 и 3.7, потом добавь 3.4. А то на выделенных 4000ккгц amd64 проблемы скриптоты менее заметны.

anonymous
()
Ответ на: комментарий от iljuase

На питоне давно не писал, но подозреваю

if str(key).startswith("kernel") == True or str(key).startswith("linux-image") == True:

можно упростить до
if str(key).startswith(("kernel","linux-image")):

zolden ★★★★★
()
Ответ на: комментарий от zolden

Да, спасибо большое, не знал! Так и сделаю.

iljuase ★★★
() автор топика
Ответ на: комментарий от zolden

Ещё наверняка можно что-то вроде key[5] in ('-','l') и избавиться от кучи тяжёлых операций. Ну это если случайного текста там не появится, а то будут случаи когда будет ошибкой. Я так кучу способов экономии процессора придумать могу.

anonymous
()
Ответ на: комментарий от Deleted

Нет, это часть скриптов по автоматизации Linux-патчинга на большой инфраструктуре: формирования патчинг-репортов, создания csv-файлов для шедулинга maintenance mode в мониторинговой системе\авторассылки e-mail кастомеру перед патчингом\автосоздания снепшотов\авторассылка Outlook-приглашений. Очередной 'никому ненужный велосипед', если говорить кратко.

https://github.com/4815162342lost/linux_patching_prepare_steps_automation

Но документации пока нет и в ближайшее время не будет.

iljuase ★★★
() автор топика
Последнее исправление: iljuase (всего исправлений: 1)
Ответ на: комментарий от menangen

Ускорение в 19 раз?!

vodka@vodka-PC:~/PycharmProjects/get_security_updates_debian$ pypy /tmp/var1.py 
1.04758501053

vodka@vodka-PC:~/PycharmProjects/get_security_updates_debian$ /tmp/var1.py 
19.420917792998807

vodka@vodka-PC:~/PycharmProjects/get_security_updates_debian$ cat /tmp/var1.py
#!/usr/bin/python3
import timeit
l=['a']*100000
def test():
    aa=True
    for i in l:
        a=i
        if aa:
            zz=i

print(timeit.timeit('test()', setup="from __main__ import test", number=10000 ))
iljuase ★★★
() автор топика
Последнее исправление: iljuase (всего исправлений: 1)
Ответ на: комментарий от iljuase

Всего-то? Я думал будет больше. Ну типа жит, все дела, говно хорошо разгоняется. Лучше взять cython, правда от жита отказаться придётся наверно. Но ускорение в 100000 раз того стоит, как вы считаете?

anonymous
()
Ответ на: комментарий от I-Love-Microsoft

Лол, такую ерунду и не знать :)

Ты как язык изучал-то?)

В пайтоне объект может возвращать True или False сам по себе, и нет смысла проверять на что равен его выхлоп.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)

На Питоне есть способы ускорить выполнение, но для этого надо хорошо его знать.

Например в случае данной темы можно попробовать подготовить данные, положить в set и потом один или 2 if к готовым данным

ism ★★★
()
Ответ на: комментарий от Deleted

Логически так более правильно. Мне кажется он имел в виду

prefix can also be a tuple of prefixes to look for

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

hanged in version 2.5: Accept tuples as prefix.

anonymous
()
Ответ на: комментарий от Deleted

Чиво?! O_o Вот эту ерунду я как раз знал, хотя язык НЕ изучал вообще. Не знал что startswith может принимать несколько аргументов, вот Qt 5 аналогичный метод принимает лишь строки чары и прочее, но не список строк. Удобно они в питошке придумали

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от iljuase

sorted

Во втором варианте .items() два раза сортируется. Это дорогая операция если там правда много элементов.

Jini ★★
()

У тебя второй вариант от первого отличается большим количеством операций. Ты сам как думаешь?

Deleted
()
Ответ на: комментарий от I-Love-Microsoft

Я вот тоже постоянно пишу на питоне и не знал, лол. Думал что можно передать только строку в качестве аргумента.

cadogan
()

подозреваю, что в реальном скрипте и тело цикла не состоит из тривиальных присваиваний

как оценивать перфоманс

померить на реальном скрипте

MyTrooName ★★★★★
()

Пишите так, чтобы код лучше читался и поддерживался. Если вы можете доказать что именно в этом месте у вас боттлнек по производительности, перепишите его НЕ на питоне.

slovazap ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.