Увеличение скорости кода Python

У меня есть код Python, в котором много классов. Я использовал cProfile , чтобы узнать, что общее время выполнения программы составляет 68 секунд. Я обнаружил, что следующая функция в классе под названием Buyers занимает около 60 секунд из этих 68 секунд. Приходится запускать программу около 100 раз, так что любое увеличение скорости поможет. Можете ли вы подсказать способы увеличения скорости, изменив код? Если вам нужна дополнительная информация, которая поможет, дайте мне знать.

def qtyDemanded(self, timePd, priceVector):
    '''Returns quantity demanded in period timePd. In addition,
    also updates the list of customers and non-customers.

    Inputs: timePd and priceVector
    Output: count of people for whom priceVector[-1] < utility
    '''

    ## Initialize count of customers to zero
    ## Set self.customers and self.nonCustomers to empty lists
    price = priceVector[-1]
    count = 0
    self.customers = []
    self.nonCustomers = []


    for person in self.people:
        if person.utility >= price:             
            person.customer = 1
            self.customers.append(person)
        else:
            person.customer = 0
            self.nonCustomers.append(person)

    return len(self.customers)

self.people - это список объектов person . Каждый человек имеет в качестве атрибутов клиента и полезность .

РЕДАКТИРОВАТЬ - ответил добавлен

-------------------------------------

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

(1) @amber - к функции обращались 80 000 раз.

(2) @gnibbler и другие - self.people - это список объектов Person в памяти. Не подключен к базе данных.

(3) @Hugh Bothwell

Суммарное время, затраченное исходной функцией - 60,8 с (обращено 80000 раз)

Суммарное время, затраченное новой функцией с локальными псевдонимами функций, как предложено - 56,4 с (просмотрено 80000 раз)

(4) @rotoglup и @Martin Thomas

Я еще не пробовал ваши решения. Мне нужно проверить остальную часть кода, чтобы увидеть места, где я использую self.customers, прежде чем я смогу внести изменения, не добавляя клиентов в список self.customers. Но я попробую и напишу ответ.

(5) @TryPyPy - спасибо за любезное предложение проверить код.

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

РЕДАКТИРОВАТЬ 2 Некоторые предположили, что, поскольку я помечаю клиентов и неклиентов в self.people , я должен попробовать без создания отдельных списков self.customers и self.noncustomers с помощью добавления. Вместо этого я должен перебрать self.people , чтобы найти количество клиентов. Я попробовал следующий код и синхронизировал обе функции ниже f_w_append и f_wo_append . Я обнаружил, что последнее занимает меньше времени, но все же 96% времени занимает первое. То есть это очень небольшое увеличение скорости.

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

Еще раз спасибо всем, кто ответил.

import numpy

class person(object):
    def __init__(self, util):
        self.utility = util
        self.customer = 0

class population(object):
    def __init__(self, numpeople):
        self.people = []
        self.cus = []
        self.noncus = []
        numpy.random.seed(1)
        utils = numpy.random.uniform(0, 300, numpeople)
        for u in utils:
            per = person(u)
            self.people.append(per)

popn = population(300)

def f_w_append():
    '''Function with append'''
    P = 75
    cus = []
    noncus = []
    for per in popn.people:
        if  per.utility >= P:
            per.customer = 1
            cus.append(per)
        else:
            per.customer = 0
            noncus.append(per)
    return len(cus)

def f_wo_append():
    '''Function without append'''
    P = 75
    for per in popn.people:
        if  per.utility >= P:
            per.customer = 1
        else:
            per.customer = 0

    numcustomers = 0
    for per in popn.people:
        if per.customer == 1:
            numcustomers += 1                
    return numcustomers

РЕДАКТИРОВАТЬ 3: Кажется, проблема в нумерации

Это ответ на то, что Джон Мачин сказал ниже. Ниже вы видите два способа определения класса Population . Я дважды запускал приведенную ниже программу, по одному для каждого способа создания класса Population . Один использует numpy, а другой не использует numpy. Один без numpy занимает столько же времени, сколько Джон обнаружил в своих прогонах. Один с numpy занимает намного больше времени. Что мне непонятно, так это то, что экземпляр popn создается до начала записи времени (по крайней мере, это то, что видно из кода). Тогда почему версия numpy занимает больше времени. И я думал, что numpy должен быть более эффективным. Во всяком случае, проблема, похоже, связана с numpy, а не с добавлением, хотя это немного замедляет работу. Может кто-нибудь подтвердить с помощью кода ниже? Спасибо.

import random # instead of numpy
import numpy
import time
timer_func = time.time # using Mac OS X 10.5.8

class Person(object):
    def __init__(self, util):
        self.utility = util
        self.customer = 0

class Population(object):
    def __init__(self, numpeople):
        random.seed(1)
        self.people = [Person(random.uniform(0, 300)) for i in xrange(numpeople)]
        self.cus = []
        self.noncus = []   

# Numpy based    
# class Population(object):
#     def __init__(self, numpeople):
#         numpy.random.seed(1)
#         utils = numpy.random.uniform(0, 300, numpeople)
#         self.people = [Person(u) for u in utils]
#         self.cus = []
#         self.noncus = []    


def f_wo_append(popn):
    '''Function without append'''
    P = 75
    for per in popn.people:
        if  per.utility >= P:
            per.customer = 1
        else:
            per.customer = 0

    numcustomers = 0
    for per in popn.people:
        if per.customer == 1:
            numcustomers += 1                
    return numcustomers



t0 = timer_func()
for i in xrange(20000):
    x = f_wo_append(popn)
t1 = timer_func()
print t1-t0

Редактировать 4: См. Ответы Джона Мачина и TryPyPy

Поскольку здесь было так много правок и обновлений, те, кто оказывается здесь впервые, могут быть немного сбиты с толку. См. Ответы Джона Мачина и TryPyPy. Оба они могут помочь в существенном повышении скорости кода. Я благодарен им и другим, кто предупредил меня о медленности append . Поскольку в этом случае я собираюсь использовать решение Джона Мачина и не использовать numpy для создания утилит, я принимаю его ответ в качестве ответа. Однако я также очень ценю направления, указанные TryPyPy.

14
задан Curious2learn 14 January 2011 в 12:03
поделиться