4

クラスの厳しいループで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()
4

2 に答える 2

5

このようなことをしなければならない場合 (関数ルックアップは実際に主要なコストですか? 乱数生成は安くはありません)、1 つのグローバル + 1 つの属性ルックアップ ( MyClass._normal) は、1 つのグローバル + 3 つの属性ルックアップ ( ) よりもそれほど安くはありませんnumpy.random.normal。あなたが本当に望むのは、ループ内でグローバルまたは属性ルックアップをゼロにすることです。これ_normal は、 function 内で定義することによってのみ行うことができます。どうしてもサイクルを減らしたい場合は、リストの追加呼び出しも事前にバインドする必要があります。

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             

  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

于 2011-12-04T18:45:58.810 に答える
2

そして、それが減速の原因になることを警戒しています。

私の懸念は正当なものですか?

場合によります。考えているアプリケーションに対して、すでに十分な速さですか? もしそうなら、心配しないでください。CPython、PyPy、NumPy、およびムーアの法則の変更により、「スローダウン」が問題になる前にその規模が緩和される可能性があります。

于 2011-12-04T18:35:54.220 に答える