2

これは確かにpython固有の質問ではありませんが、python固有の回答があれば探しています。多数の変数を含むコード ブロックを関数 (または同様のもの) に入れることです。このコードを想定してみましょう

##!/usr/bin/env python
# many variables: built in types, custom made objects, you name it.
# Let n be a 'substantial' number, say 47.
x1 = v1
x2 = v2
...
xn = vn

# several layers of flow control, for brevity only 2 loops
for i1 in range(ri1):
    for i2 in range(ri2):
        y1 = f1(i1,i2)
        y2 = f2(i1,i2)
        # Now, several lines of work

        do_some_work

        # involving HEAVY usage and FREQUENT (say several 10**3 times)
        # access to all of x1,...xn, (and maybe y1,y2)
        # One of the main points is that slowing down access to x1,...,xn
        # will turn into a severe bottleneck for the performance of the code.


# now other things happen. These may or may not involve modification
# of x1,...xn

# some place later in the code, again, several layers of flow control,
# not necessarily identical to the first occur
for j1 in range(rj1):
    y1 = g1(j1)
    y2 = g2(j1)
    # Now, again

    do_some_work  # <---- this is EXACTLY THE SAME code block as above

# a.s.o.

明らかに、「do_some_work」を関数のようなもの (またはもっと良いもの) に入れたいと思います。

Pythonでこれを行う最もパフォーマンスの高い方法は何ですか

  • 紛らわしいほど多数の引数を伴う関数呼び出しなし

  • x1、...、xnにアクセスするためのパフォーマンスの損失のある間接性なし(たとえば、それらを別のリスト、クラスなどにラップすることによって)

  • 関数 do_some_work(...) で x1,...,xn をグローバルとして使用せずに

私はいつも自分がグローバルに戻っていることを認めなければなりません。

4

3 に答える 3

1

シンプルで汚い (おそらく最適ではない) ベンチマーク:

import timeit
def test_no_func():
    (x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19) = range(20)
    for i1 in xrange(100):
            for i2 in xrange(100):
                    for i3 in xrange(100):
                            results = [x0+x1+x2+x3+x4+x5+x6 for _ in xrange(100)]
                            results.extend(x7+x8+x9+x10+x11+x12+x13+x14+x15 for _ in xrange(100))
                            results.extend(x16+x17+x18+x19+x0 for _ in xrange(500))
    for j1 in xrange(100):
            for j2 in xrange(100):
                    for i3 in xrange(100):
                            results = [x0+x1+x2+x3+x4+x5+x6 for _ in xrange(100)]
                            results.extend(x7+x8+x9+x10+x11+x12+x13+x14+x15 for _ in xrange(100))
                            results.extend(x16+x17+x18+x19+x0 for _ in xrange(500))


def your_func(x_vars):
    # of the number is not too big you can simply unpack.
    # 150 is a bit too much for unpacking...
    (x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19) = x_vars

    results = [x0+x1+x2+x3+x4+x5+x6 for _ in xrange(100)]
    results.extend(x7+x8+x9+x10+x11+x12+x13+x14+x15 for _ in xrange(100))
    results.extend(x16+x17+x18+x19+x0 for _ in xrange(500))
    return results


def test_func():
    (x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19) = range(20)
    for i1 in xrange(100):
            for i2 in xrange(100):
                    for i3 in xrange(100):
                            results = your_func(val for key,val in locals().copy().iteritems() if key.startswith('x'))
    for j1 in xrange(100):
            for j2 in xrange(100):
                    for i3 in xrange(100):
                            results = your_func(val for key,val in locals().copy().iteritems() if key.startswith('x'))


print timeit.timeit('test_no_func()', 'from __main__ import test_no_func', number=1)
print timeit.timeit('test_func()', 'from __main__ import test_func, your_func', number=1)

結果:

214.810357094
227.490054131

これは、引数の受け渡しが約 5% 遅くなります。しかし、おそらく、100 万回の関数呼び出しを導入する以上のことはできません...

于 2012-09-12T10:20:51.057 に答える
1

グローバル変数は、ローカル変数よりも大幅に遅くなります。

また、多くの異なる変数名を使用することは、ほとんど常に悪い考えです。辞書など、単一のデータ構造を使用することをお勧めします。

d = {"x1": "foo", "x2": "bar", "y1": "baz"} 

次にd、関数に渡し(辞書全体ではなく、辞書のアドレスのみが渡されるため非常に高速です)、そこからその内容にアクセスできます。

if d["x2"] = "eggs":
    d["x1"] = "spam"
于 2012-09-12T09:55:53.097 に答える
0

Python cProfile モジュールの使用をお勧めします。この方法でスクリプトを実行するだけです:

python -m cProfile your_script.py

さまざまなモード (関数ラッパーを使用する場合と使用しない場合) で、動作の速さを確認してください。変数へのアクセスがボトルネックになるとは思いません。通常、ループと繰り返し操作はそうです。

次に、i1、i2 などを使用するため、関数を抽象化することを検討することをお勧めします。

  • それらの多くの変数は、リストまたは辞書にある必要がある場合があります。
  • サイクルは itertools で抽象化できます:

    from itertools import product equal_sums = 0 for l in product(range(10), repeat=6): # range(10) の 6 つのネストされたループの代わりに if sum(l[:3]) == sum(l[3: ]): equal_sums += 1

于 2012-09-12T09:59:51.430 に答える