Ответ 1
Как общее замечание, вы можете точно увидеть, что C-код Cython генерирует для каждой исходной строки, запустив команду cython
с опцией -a
"аннотировать". См. Документацию Cython . Это очень полезно при попытке найти узкие места в теле функции.
Кроме того, существует концепция "раннее связывание для скорости" при Cython-ing вашем коде. Объект Python (например, экземпляры вашего класса Person
ниже) использует общий код Python для доступа к атрибуту, который медленный, когда во внутреннем цикле. Я подозреваю, что если вы измените класс Person
на cdef class
, вы увидите некоторое ускорение. Кроме того, вам нужно ввести объекты p1
и p2
во внутренний цикл.
Так как ваш код имеет множество вызовов Python (например, random.sample
), вы, вероятно, не получите больших ускорений, если не найдете способ поместить эти строки в C, что требует больших усилий.
Вы можете вводить вещи как tuple
или list
, но это не часто означает большую часть ускорения. Лучше использовать C-массивы, когда это возможно; то вам придется искать.
Я получаю коэффициент ускорения 1.6 с тривиальными модификациями ниже. Обратите внимание, что мне пришлось кое-что изменить здесь и там, чтобы заставить его скомпилировать.
ctypedef int ITYPE_t
cdef class CyPerson:
# These attributes are placed in the extension type C-struct, so C-level
# access is _much_ faster.
cdef ITYPE_t value, id, max_val
cdef tuple awareness_status
def __init__(self, ITYPE_t id, ITYPE_t value):
# The __init__ function is much the same as before.
self.value = value
self.id = id
self.max_val = 50000
## Initial awareness status.
self.awareness_status = (self.max_val, -1)
NPERSONS = 10000
import math
import random
class Some_class(object):
def __init__(self):
ri = lambda: random.randint(0, 10)
self.possibilities = [(CyPerson(ri(), ri()), CyPerson(ri(), ri())) for i in range(NPERSONS)]
def update_awareness_status(self, this_var, timePd):
'''Inputs: this_var (type: float)
timePd (type: int)
Output: None'''
cdef CyPerson p1, p2
price = 10
max_number = len(self.possibilities)
# self.possibilities is a list of tuples.
# Each tuple is a pair of person objects.
k = int(math.ceil(0.3 * max_number))
actual_number = random.choice(range(k))
chosen_possibilities = random.sample(self.possibilities,
actual_number)
if len(chosen_possibilities) > 0:
# chosen_possibilities is a list of tuples, each tuple is a pair
# of person objects. I have included the code for the Person class
# below.
for persons in chosen_possibilities:
p1, p2 = persons
# awareness_status is a tuple (float, int)
if p1.awareness_status[1] < p2.awareness_status[1]:
if p1.value > p2.awareness_status[0]:
p1.awareness_status = (this_var, timePd)
else:
p1.awareness_status = p2.awareness_status
elif p1.awareness_status[1] > p2.awareness_status[1]:
if p2.value > p1.awareness_status[0]:
p2.awareness_status = (price, timePd)
else:
p2.awareness_status = p1.awareness_status