Pythonプログラムの優先度を変更するコード例です。決算分析システムでは、大量のXBRLを読み込んで数字を取り出したり、大量のグラフを描いたりします。
これらは大抵、マルチプロセス処理ですべてのCPUを動員して、全力で作業にあたってもらうのですが、そのあいだは他の作業が難しくなります。そこで、プログラム開始直後にパイソンプロセスの優先度を下げる、というようなことをよくしています。
マルチプロセス処理時の作業を快適にする
私はウィンドウズですが、ふだん優先度「通常」になっているところを、「低」に下げてあげます。親の優先度を下げてあげれば、マルチプロセス処理で現れる子プロセスも優先度が下がった状態で開始されます。
こうすることで、フルパワー時に他のデバッグ作業などを始めても、さくさく快適になりました。すぐにCPUを分けてくれます。その間も、元のプログラムは空いているCPUを使い切ってくれるので、CPUは常に100%です。
それで、優先度「通常」⇒「低」に下げた時の実行時間ですが、ログに記録した実行時間を見てきた限り、特に遅くなっている様子はありませんでした。ほかの作業をしていなければ、「通常」時とほぼ同じ時間で完了するようです。
psutil で優先度を変更
優先度の変更には、「psutil」というパイソン用モジュールを使用します。私はピー・エス・ユーティルって呼んでいます。
公式サイトのドキュメントです。
psutil documentation
https://psutil.readthedocs.io/en/latest/
インストール
pip でインストールします。
pip install psutil
一応、アンインストール方法です。
pip uninstall psutil
実行すると、削除前に「Proceed (y/n)?」と聞かれますので、「y」を入力してエンターキーを押します。これでアンインストール完了です。
優先度「低」に下げるコード例
ナイスにアイドル・プライオリティー・クラスを渡すと「低」になります。設定が済めばインスタンス「p」は使わないので、削除しています。
決算分析システムでは、これを関数にして、色々なプログラムの先頭で簡単に優先度を下げられるようにしています。
import psutil
p = psutil.Process()
p.nice(psutil.IDLE_PRIORITY_CLASS)
del p
プロセスクラスとナイスメソッドの説明ページです。
class psutil.Process(pid=None)
https://psutil.readthedocs.io/en/latest/#psutil.Process
pidを省略すると、os.getpid()のPIDが使われるとのことです。
現在のプロセスIDに関する設定・情報取得が可能になります。
nice(value=None)
https://psutil.readthedocs.io/en/latest/#psutil.Process.nice
値を渡せば優先度を設定、省略すると優先度を取得。
ほかの優先度に変えるコード例
優先度を高、通常以上、通常、通常以下、低に変えるコード例です。
優先度が変わっていく様子は、タスクマネージャーでも確認できます。該当する「プロセスID(PID)」を見ると、「基本優先度」列の表示が変わっていくはずです。
os.system('PAUSE')
は一時停止するためのコードです。
import os
import psutil
def main():
"""プロセスの優先度変更テスト"""
print('start\n')
# プロセスクラスのインスタンス作成
p = psutil.Process()
# 現在の「プロセスID」と「優先度」を表示
print('PID: %s 優先度: %s\n' % (p.pid, p.nice()))
os.system('PAUSE')
# 優先度: 高 (ハイ・プライオリティ)
p.nice(psutil.HIGH_PRIORITY_CLASS)
print('PID: %s 優先度: %s\n' % (p.pid, p.nice()))
os.system('PAUSE')
# 優先度: 通常以上 (アボーブ・ノーマル・プライオリティ)
p.nice(psutil.ABOVE_NORMAL_PRIORITY_CLASS)
print('PID: %s 優先度: %s\n' % (p.pid, p.nice()))
os.system('PAUSE')
# 優先度: 通常 (ノーマル・プライオリティ)
p.nice(psutil.NORMAL_PRIORITY_CLASS)
print('PID: %s 優先度: %s\n' % (p.pid, p.nice()))
os.system('PAUSE')
# 優先度: 通常以下 (ビロウ・ノーマル・プライオリティ)
p.nice(psutil.BELOW_NORMAL_PRIORITY_CLASS)
print('PID: %s 優先度: %s\n' % (p.pid, p.nice()))
os.system('PAUSE')
# 優先度: 低 (アイドル・プライオリティ)
p.nice(psutil.IDLE_PRIORITY_CLASS)
print('PID: %s 優先度: %s\n' % (p.pid, p.nice()))
os.system('PAUSE')
del p
# ここに実行したい処理を書く
print('end')
return
if __name__ == '__main__':
main()
実行結果です。プロセスIDは実行するごとに変わります。
start
PID: 5480 優先度: Priority.NORMAL_PRIORITY_CLASS
続行するには何かキーを押してください . . .
PID: 5480 優先度: Priority.HIGH_PRIORITY_CLASS
続行するには何かキーを押してください . . .
PID: 5480 優先度: Priority.ABOVE_NORMAL_PRIORITY_CLASS
続行するには何かキーを押してください . . .
PID: 5480 優先度: Priority.NORMAL_PRIORITY_CLASS
続行するには何かキーを押してください . . .
PID: 5480 優先度: Priority.BELOW_NORMAL_PRIORITY_CLASS
続行するには何かキーを押してください . . .
PID: 5480 優先度: Priority.IDLE_PRIORITY_CLASS
続行するには何かキーを押してください . . .
end