Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Профилирование и отладка Python, инструменты

Anna | 16.06.2014 | нет комментариев

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

Сегодня мы познакомимся с стержневой и самой многочисленной группой инструментов — событийными профайлерами.

Задача для тренировки

В прошлой статье мы разбирали задачу 3 из Плана Эйлера. Для многообразия возьмём какой-нибудь иной пример, скажем, задачу 7 из этого же альманаха задач:

Выписав первые шесть примитивных чисел, получим 2, 3, 5, 7, 11 и 13. Видимо, что 6-ое примитивное число — 13.
Какое число является 10001-ым простым числом?

Пишем код:

"""Project Euler problem 7 solve"""
from __future__ import print_function
import math
import sys

def is_prime(num):
    """Checks if num is prime number"""
    for i in range(2, int(math.sqrt(num))   1):
        if num % i == 0:
            return False
    return True

def get_prime_numbers(count):
    """Get 'count' prime numbers"""
    prime_numbers = [2]
    next_number = 3

    while len(prime_numbers) < count:
        if is_prime(next_number):
            prime_numbers.append(next_number)
        next_number  = 1

    return prime_numbers

if __name__ == '__main__':
    try:
        count = int(sys.argv[1])
    except (TypeError, ValueError, IndexError):
        sys.exit("Usage: euler_7.py number")
    if count < 1:
        sys.exit("Error: number must be greater than zero")

    prime_numbers = get_prime_numbers(count)
    print("Answer: %d" % prime_numbers[-1])

Помним, что код не безупречен, и многие вещи дозволено сделать проще, отменнее, стремительней. Именно в этом заключается цель данной статьи =)

В прошлой статье я оконфузился и не сделал самого значимого: тестов. На самом деле поломать программу в процессе рефакторинга либо оптимизации легче простого, и всякий цикл профилирования и переписывания кода должен в непременном порядке сопровождаться тестированием функционала (как непринужденно затронутого изменениями, так и каждого остального, чай сайд-результаты такие сайд-результаты). Испробуем исправиться и добавим тесты в нашу программу. Самый примитивный и подходящий для такого простого скрипта вариант — применять модуль doctest. Добавляем тесты и запускаем их:

Тесты

"""Project Euler problem 7 solve"""
from __future__ import print_function
import math
import sys

def is_prime(num):
    """
    Checks if num is prime number.

    >>> is_prime(2)
    True
    >>> is_prime(3)
    True
    >>> is_prime(4)
    False
    >>> is_prime(5)
    True
    >>> is_prime(41)
    True
    >>> is_prime(42)
    False
    >>> is_prime(43)
    True
    """
    for i in range(2, int(math.sqrt(num))   1):
        if num % i == 0:
            return False
    return True

def get_prime_numbers(count):
    """
    Get 'count' prime numbers.

    >>> get_prime_numbers(1)
    [2]
    >>> get_prime_numbers(2)
    [2, 3]
    >>> get_prime_numbers(3)
    [2, 3, 5]
    >>> get_prime_numbers(6)
    [2, 3, 5, 7, 11, 13]
    >>> get_prime_numbers(9)
    [2, 3, 5, 7, 11, 13, 17, 19, 23]
    >>> get_prime_numbers(19)
    [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67]
    """
    prime_numbers = [2]
    next_number = 3

    while len(prime_numbers) < count:
        if is_prime(next_number):
            prime_numbers.append(next_number)
        next_number  = 1

    return prime_numbers

if __name__ == '__main__':
    try:
        count = int(sys.argv[1])
    except (TypeError, ValueError, IndexError):
        sys.exit("Usage: euler_7.py number")
    if count < 1:
        sys.exit("Error: number must be greater than zero")

    prime_numbers = get_prime_numbers(count)
    print("Answer: %d" % prime_numbers[-1])

 

Запуск тестов и итог

range вызывается 104741 раз, а верхняя граница диапазона при всяком вызове инкрементируется (перебираем числа ступенчато), дозволено сделать итог, что длина списка, создаваемого функцией range достигает сотни тысяч элементов к концу работы программы и список создаётся огромнее ста тысяч раз. Почитав ещё документацию мы узнаём, что нам следует применять функцию xrange в этом цикле (внимательный читатель должен ощутить сарказм в этом месте, чай всякий питонист знает про range VS xrange). Плюсом замены range на xrange будет так же очевидная экономия памяти (эту теорию мы проверим позднее). Заменяем, запускаем тесты: всё ок, запускаем профайлер:
method 'append' of 'list' objects}
        1    0.138    0.138    1.018    1.018 euler_7.py:44(get_prime_numbers)

 Консоль, безусловно, отличная штука, но не дюже наглядная. В особенно трудных обстановках, в программах с сотнями и тысячами вызовов обзор итогов представляется затруднительным. Так уж устроены люди, что графическую информацию нам (в различие от компьютеров) воспринимать значительно проще, чем текстовую. На поддержка приходят разные инструменты для обзора итогов профилирования.

kcachegrind


 Начну, вероятно, с такого знаменитого инструмента, как kcachegrind, тот, что, на самом деле, предуготовлен для визуализации итогов утилиты Callgrind, но переконвертировав итоги Python-профалера, их дозволено открыть в kcachegrind. Конвертирование выполняется с поддержкой утилиты pyprof2calltree:
00004ms.1374074996.prof
static.js.jquery-2.0.2.min.js.000001ms.1374074996.prof
user.login.000187ms.1374075001.prof

 Последующий обзор дозволено исполнить с поддержкой всякого из инструментов, перечисленных выше: pstats, kcachegrind, RunSnakeRun либо gprof2dot. Либо всякого иного =)

 Помимо встроенного в Python профайлера имеется так же масса сторонних программ, примитивных и трудных, пригодных и не дюже.

pycallgraph


pycallgraph разрешает строить дерево вызовов программы Python. Ставим:
s_permark!    next_number = 3

    while len(prime_numbers) < count:
        if is_prime(next_number, prime_numbers):
            prime_numbers.append(next_number)
        next_number  = 1

    return prime_numbers

 Запускаем тесты, убеждаемся, что всё отрабатывает верно, замерим время выполнения программы:
комментариях.

В дальнейшей статье мы познакомимся с способами и инструментами для отладки Python-программ. Оставайтесь на связи!

Минута статистики: в трёх статьях про профилирование питона я применял слово «профилирование» огромнее ста раз.


Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB