garicchi最近なぜかパフォーマンスチューニングに興味があり、この本を読んでいる。pocketsハイパフォーマンスPythonhttps://www.oreilly.co.jp/books/9784873117409Pythonの高速化技法について一歩踏み込んだプロユースの解説書。高性能なPythonを理解する1章ではパフォーマンスチューニングにおいて知っておくべきコンピュータアーキテクチャの基礎と、それに関わるPythonについて書いてあるコンピュータシステムの基礎コンピューターは簡単に言うと、「演算装置(ALU)」「記憶装置(RAM,ROM)」「両者の接続装置(BUS)」から構成されている演算装置は、ビット列を入力とし、変換し、別のビット列を出力する関数のようなものと考えることができる。演算装置の特性としては、「1サイクルあたりに処理できる命令数(IPC)」と「1秒間あたりに処理できる数(クロック周波数)」の2つがある。IntelのCoreシリーズはIPCに優れているがクロックは弱い。PentiumシリーズはIPCは弱いがクロックは強い。複数のデータを1度に入力し、計算することをベクトル化と呼ぶ。ベクトル化を行うとIPCが上がる。ここ10年ではIPCやクロック周波数は頭打ちになってきている。そこでチップメーカーはハイパースレッディング(2つの命令を1つのCPUで実行する)やアウトオブオーダー(実行順序に依存しない処理を最適化する)など工夫をしている。アムダールの法則とはいくら複数コアで処理を並列化しても単一コアでしか処理できない部分がボトルネックになってしまうこと。Pythonの場合であれば、グローバルインタプリタロックによって複数スレッドで実行しても1度に実行できるのは1つの命令のみであり、性能がわるい。(マルチプロセスなら関係ない?)記憶装置については、多数のちいさなデータよりも大きな1つのデータを扱う方が効率が良い。一般的に記憶装置の速度と容量は反比例の関係にあり、L1,L2キャッシュ、RAM、ROMのように多層化することで速度を確保している。データを見つけるまでのレイテンシも重要。接続装置については、データ転送のスピードが重要。L1、L2キャッシュと接続しているバスは速い。GPUなどの周辺デバイスへのアクセスは遅い。特性としては、「1回にどれだけの量を転送できるか(バス幅)」と「1秒間に何回転送できるか(バス周波数)」。ベクトル化されていると、1回に転送する量が増えるので早くなる。パフォーマンスとしてのPythonPythonのインタプリタはコンピュータアーキテクチャの底レイヤな部分を高度に抽象化する。これはアイデアの実装スピードとのトレードオフなので、Pythonの実装の楽さを求めるなら性能は落ちる。普通にPythonを使っているだけではベクトル化は難しい。numpyなどのツールを使う必要がある。Pythonはガベージコレクションを備えた言語なのでヒープの自由な位置にメモリを確保し、破棄されるタイミングはGCによる。よってメモリの断片化が生じ、メモリの最適化が難しくなる。gccのコンパイラはコンパイルすることによって最適化処理をする。Pythonはコンパイルしないし、動的型付けなので実行時まで処理がわからない。それでも、Pythonを使うのはCで書かれた安定したライブラリが多く存在するから。アイデアを即時にプロトタイピングできること。ボトルネック発見のためのプロファイリングジュリア集合プロファイリングのサンプルコードとしてジュリア集合のコードがあるがはっきりいってジュリア集合の理論はわからなかった。サンプルコードは以下にある。timeしてtime.time()で時間を計測しましょうという話。いちいち計算がめんどかったらデコレータを書きましょうPythonのtimeitモジュールを使うとn回のループをr回反復し、かかった時間を計測してくれる。\"hoge\""timeコマンドおなじみunixのtimeコマンドで楽に全体の実行時間を計測できる。結果はreal(経過時間)とuser(カーネル関数以外)とsys(カーネル関数)で表示されるがreal-(user+sys)でどれだけIO待ちがあったかがわかる。faultの回数もみることができる。faultが増えると実行時間がおそくなるぞ。cProfileモジュールpython組み込みのプロファイラ。各関数にかかった時間と呼び出し回数、単位回数あたりにかかった時間が表示される。runsnakerunというモジュールを使うとcProfileの結果を可視化できる。line_profilerサードパーティモジュール。行ごとの実行時間を計測してくれる。Pythonは式を基本左から右に評価するので式の左側に計算コストの低い処理を置くのは合理的memory_profilerサードパーティ製メモリプロファイラ。行単位でメモリ使用量を表示してくれる。mprofというユーティリティを使うと結果をグラフ化できる。heapy処理の途中に挟むことでヒープの使用量を表示してくれる。guppyパッケージに入っている。dowser変数の生成状況を可視化してくれる。Webブラウザ上でみる。disPythonの各処理で生成される低レベルなコードを表示してくれる。自前で関数を書くより、組み込み関数を使った方が圧倒的に速い。