Python パフォーマンス最適化の例題演習 2 - 詳細な最適化 (ctypes など、未完成)

この章では、Fernando Doglio によって書かれた「Python Performance Analysis and Optimization」の知識体系を引き続き使用し、主に最適化の詳細に基づいて、独自の実用的なアプリケーションと組み合わせます.ctypes の使用に焦点を当てています.

関数戻り値キャッシュ/関数参照テーブル

デフォルトパラメータの使用

既定のパラメーター (既定の引数) は、実行時に入力を決定するのではなく、関数の作成時に入力値を決定できます。

ここで Python パラメーターを確認します。

  1. 位置引数

  2. キーワード引数

    def trapezoid_area(base_up, base_down, height)
    	return 1/2 * (base_up + base_down) * height
    
    trapezoid_area(1, 2, 3) # 位置参数
    trapezoid_area(base_up=1, base_down=2, height=3) # 关键词参数
    trapezoid_area(height=3, base_down=2, base_up=1) # right
    trapezoid_area(height=1, base_down=2, 1) # wrong
    trapezoid_area(base_up=1, base_down=2, 3) # right
    trapezoid_area(1, 2, height=3)
    
  3. デフォルトのパラメータ

    デフォルトパラメータ=デフォルト値、関数が呼び出されたとき、デフォルトパラメータの値が渡されない場合、デフォルト値と見なされます。

    デフォルト パラメータは、位置パラメータの後に。そうしないと、プログラムがエラーを報告します。

    def trapezoid_area(base_up, base_down, height=3)
    	return 1/2 * (base_up + base_down) * height
    trapezoid_area(1, 2) 
    trapezoid_area(1, 2, height=3) # 位置参数
    
  4. 可変引数

    可変パラメーターとは、渡されるパラメーターの数が可変であり、0、1、2 の任意の数であり、可変長パラメーターであることを意味します。

    def printinfo(arg1, *args): # *args - 可变参数,可以是从零个到任意个,自动组装成元组。
        print('arg1:' + str(arg1))
        print('args:', end=' ')
        for var in args:
            print(var, end=' ')
        print(' ')
    
    
    printinfo(10)  # 10
    printinfo(70, 60, 50)
    

    プログラムを実行した結果は次のとおりです。

    arg1:10
    args:  
    arg1:70
    args: 60 50  
    
    Process finished with exit code 0
    
  5. キーワード引数

    def printinfo(arg1, *args, **kwargs): # **kwargs - 关键字参数,可以是从零个到任意个,自动组装成字典。
        print(arg1)
        print(args)
        print(kwargs)
    
    
    printinfo(70, 60, 50)
    # 70
    # (60, 50)
    # {}
    printinfo(70, 60, 50, a=1, b=2)
    # 70
    # (60, 50)
    # {'a': 1, 'b': 2}
    

    プログラム中のコメント部分が実行結果です。

  6. 名前付きキーワード引数 (name キーワード引数)

    • *, nkw- nkw の前にセパレーターを追加することによって定義される、ユーザーが入力したいキーワード・パラメーターである名前付きキーワード・パラメーター*
    • キーワード パラメータの名前を制限する場合は、「名前付きキーワード パラメータ」を使用できます。
    • 名前付きキーワード パラメータを使用する場合は、パラメータ名が欠落していないことに特に注意してください。
    def printinfo(arg1, *, nkw, **kwargs):
        print(arg1)
        print(nkw)
        print(kwargs)
    
    
    printinfo(70, nkw=10, a=1, b=2)
    # 70
    # 10
    # {'a': 1, 'b': 2}
    
    printinfo(70, 10, a=1, b=2)
    # TypeError: printinfo() takes 1 positional argument but 2 were given
    
  7. パラメータの組み合わせ

    To define a function in Python, you can use positional parameters, default parameters, variable parameters, named keyword parameters, and keyword parameters. これら 5 種類のパラメーターのうち 4 つは一緒に使用できますが、パラメーター定義の順序は次のようにする必要があることに注意してください。

    • 位置引数、デフォルト引数、可変個引数、およびキーワード引数。
    • 位置引数、デフォルト引数、名前付きキーワード引数、およびキーワード引数。

    可変長引数とキーワード引数を定義するための構文に注意してください。

    • *argsargsこれは可変パラメータであり、tuple
    • **kwargskwを受け取るキーワード引数です。dict

    名前付きキーワード パラメータは、デフォルト値を提供しながら、呼び出し元が渡すことができるパラメータ名を制限するために使用されます。名前付きキーワード parameter を定義するときは、区切り文字を忘れずに記述してください*。そうしないと、定義は位置パラメーターになります。

    警告: 最大 5 つの引数を組み合わせることができますが、同時に多くの組み合わせを使用しないでください。関数が混乱する可能性があります。

リスト合成式ビルダー

プログラム計算の前に初期化などの操作を配置し、for ループをリスト合成式に置き換えます。

final_state_list = [FinalStatus() for x in range(opt.multiple_camera_number)]

ctypes

ctypes ライブラリを使用すると、開発者は Python の最下層に直接アクセスし、C 言語の力で開発できます。このライブラリは、このバージョンが C 言語で記述されているため、正式バージョンのインタープリター (CPython) でのみ使用できます。PyPy や Jython などの他のバージョンは、このライブラリにアクセスできません。

この時点で、キー コードを C 言語で記述し、ライブラリにコンパイルしてから、モジュールとして Python にインポートできます。

どの python インタープリターかを判断する方法元のテキストのコードを変更しました。自分の python 環境で cv を実行して、どのインタープリターが使用されているかを確認するだけです。

import sys
import os
try:
    from platform import python_implementation
except ImportError: # pragma: no cover
    def python_implementation():
        """Return a string identifying the Python implementation."""
        if 'PyPy' in sys.version:
            print('PyPy')
        if os.name == 'java':
            print('Jython')
        if sys.version.startswith('IronPython'):
            print('IronPython')
finally:
    print('CPython')

ctypes の使用

ctypesの使い方について、いくつかの記事を読んで少し複雑に感じました.個人的には、ctypesの使い方は、純粋なcコードを外部リンクライブラリにコンパイルし、この外部リンクライブラリを使用するパイソン。

最初のステップ: 最初に ctypes_test.c を作成します

// 这是找素数的程序
#include <stdio.h>
#include <math.h>
int check_prime(int a)
{
    
    
    int c;
    for ( c = 2 ; c <= sqrt(a) ; c++ ) {
    
    
        if ( a%c == 0 )
        return 0;
    }
    return 1;
}

ステップ 2 : ファイルをコンパイルする

$ gcc -shared -o ct.so -fPIC .\ctypes_test.c

私の環境はanacondaにあり、gccがインストールされていますgcc version 8.1.0 (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project).gccのパラメータに関するいくつかの補足:

パラメータ 関数
-共有 このオプションは動的ライブラリの使用を禁止するため、コンパイルされたものは一般に非常に大きく、動的リンク ライブラリなしで実行できます。
-静的 このオプションはダイナミック ライブラリを使用しようとするため、生成されるファイルは比較的小さくなりますが、システムにはダイナミック ライブラリが必要です。
-fPIC それはダイナミック リンク ライブラリですか。

ステップ 3 : 生成されたライブラリを python プログラムで呼び出す

import time
import ctypes
import math
# ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)
check_primes_types = ctypes.CDLL('./ct.so').check_prime  # ctypes.CDLL('路径').函数名

def check_prime(x):
    values = range(2, int(math.sqrt(x)))
    for i in values:
        if x % i == 0:
            return False
    return True


init = time.time()
numbers_py = [x for x in range(1000000) if check_prime(x)]
print("Full python version: %s seconds" % (time.time() - init))
init = time.time()
numbers_c = [x for x in range(1000000) if check_primes_types(x)]
print("C version: %s seconds" % (time.time() - init))
print(len(numbers_py))

予防

戻り値:ctypesがdllを呼び出す際の引数の型と戻り値の型について

パラメータ: python は c/c++ コードを呼び出して解決します ctypes.ArgumentError: 引数 1: クラス 'TypeError': 変換方法がわかりません

パラメータは配列です: ctypes の使用 (numpy 配列を c に渡す)

文字列連結

文字列は不変であるため、文字列の内容を変更するために何かを行うと、実際には新しい内容で新しい文字列が作成され、変数は新しく作成された文字列を指します。

リスト内の文字列を結合する

full_doc = ""
for word in word_list:
	full_doc += word

と書き直した

full_doc = "".join(world_list)

可変補間

document = "%s%s%s%s" % (title, introduction, main_piece, conclusion)

その他の Python 最適化のヒント

不要なプログラムを削除する

# 173行
imc = im0.copy() if opt.save_crop else im0  # for save_crop

おすすめ

転載: blog.csdn.net/weixin_42442319/article/details/127751793