Помещение функции в локальное пространство имен для ускорения доступа с учетом дескрипторов - PullRequest
4 голосов
/ 04 декабря 2011

Я использую numpy.random.normal функцию в жестком цикле в классе.

class MyClass(MyBaseClass):   
    def run(self):
        while True:
            ...
            self.L.append(numpy.random.normal(0,1))

Я знаю, что в Python довольно медленно использовать несколько поисков. В numpy.random.normal есть 3 поиска: сначала ищется numpy, затем random, а затем normal.

Поэтому я решил решить эту проблему, присвоив numpy.random.normal локальной переменной _normal.

Вот и мы:

class MyClass(MyBaseClass):
    _normal = numpy.random.normal
    def run(self):
        while True:
            ...
            self.L.append(MyClass._normal(0,1))

Что меня действительно беспокоит, так это дескрипторы. Когда к переменной в классе обращаются, все базовые классы ищутся для дескриптора данных с тем же именем. Здесь описано :

Проверьте objectname.__class__.__dict__ для имени пользователя. Если он существует и является дескриптором данных, вернуть результат дескриптора. Поиск по всем базам objectname.__class__ для одного и того же случая.

Итак, я полагаю, если я поставлю _normal в локальном пространстве, как я это делал выше, будет случай поиска всех базовых классов для дескриптора данных. И я опасаюсь, что это станет источником замедления.

Оправданы ли мои опасения?

Должен ли я беспокоиться о времени, которое требуется для поиска дескрипторов в базовых классах?

И есть ли лучший способ ускорить доступ к функции, расположенной глубоко в модуле, когда она используется в классе?


В комментариях к ответам было обсуждение.

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

На самом деле, код ближе к этому (он очень очень упрощен):

class MyClass(MyBaseClass):

    def __iter__(self):
        return self

    def next(self):
        self.L.append(numpy.random.normal(0,1))   

    def run(self):
        while True:
            self.next()

Ответы [ 2 ]

5 голосов
/ 04 декабря 2011

Если вам нужно сделать что-то подобное (действительно ли поиск функций является доминирующей стоимостью? Генерация случайных чисел недешева), вы должны понимать, что один глобальный + один поиск по атрибуту (MyClass._normal) не намного дешевле, чем один глобальный +три attr поиска (numpy.random.normal).Что вам действительно нужно, так это получить ноль глобальных или attr запросов внутри цикла, что вы можете сделать, только определив _normal внутри функции .Если вы действительно отчаянно нуждаетесь в сокращении циклов, вам также следует добавить в список вызов addnd:

class MyClass(MyBaseClass):
    def run(self):
        _normal = numpy.random.normal
        _Lappend = self.L.append
        while True:
            ...
            _Lappend(_normal(0,1))

Контрастный вывод разборки (только для оператора append):

  LOAD_FAST                0 (self)
  LOAD_ATTR                1 (L)
  LOAD_ATTR                2 (append)
  LOAD_GLOBAL              3 (numpy)
  LOAD_ATTR                4 (random)
  LOAD_ATTR                5 (normal)
  LOAD_CONST               1 (0)
  LOAD_CONST               2 (1)
  CALL_FUNCTION            2
  CALL_FUNCTION            1
  POP_TOP             

vs

  LOAD_FAST                2 (_Lappend)
  LOAD_FAST                1 (_normal)
  LOAD_CONST               1 (0)
  LOAD_CONST               2 (1)
  CALL_FUNCTION            2
  CALL_FUNCTION            1

Что было бы еще лучше, так это векторизация - создание множества случайных нормальных отклонений и добавление их в список за один раз - это можно сделать с помощью аргумента size для numpy.random.normal.

2 голосов
/ 04 декабря 2011

И я опасаюсь, что это станет источником замедления.

Оправданы ли мои опасения?

Это зависит.Это уже достаточно быстро для приложения, которое вы имеете в виду?Если так, не волнуйтесь.Изменения в CPython, PyPy, NumPy и законе Мура, вероятно, уменьшат величину «замедления», прежде чем оно станет камнем преткновения.

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