76回生 まふまふ
76回生のまふまふです(^^♪.まだ知らないことも多いのでよろしくお願いします.
僕は主にPythonを使っているので,Pythonについて書こうと思ったのでこの内容にしました.
Pythonを使ったことがない人やプログラミングを知らない人でも,面白そうだなぁと思ってくれたら嬉しいです.
特にプログラミングをしたことがない人はPythonから始めることをお勧めします(^^♪
いきなりC言語*1やJava(⇦プログラミング言語のひとつ)からなどから始めようとすると,難しくてあきらめてしまうかもしれません.
Pythonなら初心者でもわかりやすいような簡単な文法なので,簡単に始められます.
もちろん他の言語のような高度なこともできるため,機械学習などにも生かせるため最近人気です!
今回はこの言語の唯一の欠点の『速度が遅い』ことを克服するため,高速化について書こうと思います.
Pythonがどういうものか知らない方も目を通していただけたら嬉しいです.
そんなに長くないので...汗
Pythonが遅い理由はいくつかあります.
Pythonはインタープリタ型言語といって実行するときに一行ずつ機械語に翻訳されていきます.
なのでC言語などのコンパイル型言語*2とくらべてかなり速度が低下します(;´・ω・)
Pythonでは変数宣言(型を明確に表記して,変数を使用すること)が不要で,いきなりソースコードの中で新しい変数を使用することができます.
※変数とは値(整数,文字列など...)を保存する箱みたいなもの(?)です.数学の変数とは意味が違います.
なので変数を使った操作で毎回型チェックが行われます.⇦遅くなる原因
これ以外にもたくさんの理由がありますが,主な理由はここに挙げた二つです.
どうにかして速くできないですかねぇ...)
理由の一つにループ処理(繰り返しの処理)が遅いことがあります.型指定を行わないせいで,ループ時にも型のチェックが必要となってすごく遅くなるんですね.
どうすれば遅いものが速くなるの??と,思うでしょう(多分.
しかしPythonのままで高速化する方法があるんです.
※速度計測環境
[pc]:CPython&C++:Windows 10,Cython&PyPy:Ubuntu,[Python]:Python3.7
※比較に使うPythonのコード
cpython.py
from time import time def mf():#関数の定義 a=0; for i in range(100000): a+=1; st=time(); mf(); en=time() print("%s[sec]"%(en-st)); if __name__=="__main__":#呼び出されたら実行する mf()
速度は0.0047[sec]でした.
※CPythonとはCで作られたPythonのことで,これが通常のPythonです.
これ以外にはRPythonなどがあります.
(Cで作られているのに遅いのは納得いかないな
NumPyというライブラリ(これを読み込むことでその機能を使用できる)があります.
このライブラリはC言語でつくられています.(速い理由)
これを使用すると高度な計算なども高速に行うことができます!!
pipコマンド(Pythonをダウンロードすると,コマンドプロンプトから使用できます)を使ってpip install numpy
で使えるようになります.(簡単ですね!!
そしてimport文(必要なライブラリを読み込むコード)でimport numpy
とすると使えます.
計算に限られるため,ほかの方法との比較はできません.次のに期待しましょう)
次はNumbaライブラリのJITコンパイル*3を使う方法です.
この方法では主にNumPyを扱ったプログラムが大幅に高速化します.JIT技術を使ってコンパイルされます.⇦速い原因
NumPyを使わないプログラムではあまり効果がないことがありますが,ループ処理のあるものは速くなることがあります.
pipコマンドを使ってpip install numba
で使えるようになります.デコレータ*4を使って
jit_.py
from numba import jit#import numbaで関数前で@numba.jitでもok @jit def mf():#mf には定義したい関数名を #....
とすると自動でその関数がコンパイルされます.
NumbaのJITを使う上での注意は一回目は速くならないことです.
二回目以降の呼び出し時にはすでに一回目のときにコンパイルされているため,速く処理を行えますけどね.
計測しまーす!
numba_.py
from time import time from numba import jit @jit def mf(): a=0; for i in range(100000): a+=1; st=time(); mf(); en=time() print("%s[sec]"%(en-st)); if __name__=="__main__": mf()
速度はPython:0.0047[sec],Numba:0.0674[sec]
ということで残念ながら速くなりませんでした.やはりNumPy用なのかなぁ...
※ファイル名の最後に"_"をつけているのは自分自身をNumbaというライブラリとして読み込まないようにするためです.Pythonでは優先度を分ける書き方がないので^^;
今までは計算だけ!とかNumPyをつかったものだけ!などでしたが,今回はどのようなプログラムにも適用できて速いです!!!
Cythonは一種のプログラミング言語です.しかしPythonとの高い互換性があり,多くのコードはそのままでも使えます.
Cythonがなぜ速くなるのかというと,コンパイルするからです.また型指定(変数宣言)もできます.
望み通りの素晴らしい言語ですねぇ(笑)
Pythonのライブラリも幅広く対応しており便利です.
pipコマンドを使ってpip install cython
で使えるようになります.※管理者権限が必要です
どのようにすると使えるのかというと,まず記述したコードを.pyx
という拡張子で保存します.
その後cython mf.pyx
で.c
ファイルに変換します.(mf.pyxには任意のファイルを指定)
さらに,これによって生成された.c
ファイルをCのコンパイラ*5を使用して.pyd
(Mac,Linuxでは.so
)にコンパイルします.
これにより,Pythonからimportするだけで簡単に使える高速なライブラリができます.
このファイルは共有ライブラリといい,C,Pythonなどから使用できるライブラリです.
(Jupyter Notebook*6を使って対話的にCythonを使用することもできます.この場合,自分でコンパイルする必要はありません)
で,終わろうと思ったのですが手元の環境では上記の方法ではエラーとなったので,もう一つの方法を紹介します!
setup.py
from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext ext_modules = [Extension("mf", ["mf.py"])] setup( name = 'mf', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules )
このような内容のsetup.pyを用意します.
そしてコマンドプロンプトからそのフォルダに移動し(cdコマンドを使用)て,python setup.py build_ext --inplace
と入力します.
すると,.py
ファイルから.pyd
または.so
に直接変換できます!!
※Visual Studioがインストールされている必要があります.
(;;) なんで両方できないんだぁ-(基本はできますのでご心配なく...)
Cythonでこのコードを実行してみます.
cython.pyx
from time import time def mf(): a=0; for i in range(100000): a+=1; st=time(); mf(); en=time() print("%s[sec]"%(en-st)); if __name__=="__main__": mf()
※残念なことにcython mf.pyx
を実行したときにlanguage_level
でエラーが発生しました.基本はcython language_level=3
できるはずなのですができませんでした.前のPCではできたのに...
PyPyはCPython(CPythonとはCで作られたPythonです.つまり一般的なPythonのことです)より速いというのがうりです.
Numbaと同じようにJIT技術を使います.ただ,一つ問題がありCでつくられたライブラリが使えないことです(RPython特有なので仕方ないです).しかし,NumPyなどの主要ライブラリはPyPy版があり,ある程度フォローされています!!
PyPy2,PyPy3はAtCoder*7の言語にもあります.言語なのかは怪しいですが)※Cythonはありません
単なるPythonのコードでもPyPyとして提出することで実際にPythonでは実行時間超過だったコードが正解となることもあるようです.
PyPyではここが重要です.aptコマンドが使える環境ではapt install pypy
でインストールできるのですが,Windows等の場合は公式サイトからファイルをダウンロードする必要があります.
Python3の場合はPyPy3なのでPyPy3をダウンロードしてください.
これをコマンドラインから使用するには自分でパスを通す必要があります.
使用するにはpypy mf.py
とします.mfの部分には任意のファイル名を指定してくださいね!
これで使用できます.
pypy.py
from time import time def mf(): a=0; for i in range(100000): a+=1; st=time(); mf(); en=time() print("%s[sec]"%(en-st)); if __name__=="__main__": mf()
速度はPython:0.0047[sec],PyPy:0.0010[sec]
速くなりましたね!
もし'pip' は,内部コマンドまたは外部コマンド,操作可能なプログラムまたはバッチ ファイルとして認識されていません.
とでた場合はpipがインストールできていないのでapt install python-pip
でダウンロードできます.※Windowsでのメッセージ.Macの場合は-bash: pip: command not found
※PyPyやPython2が入っている場合になることがあります.
速度が変わらなかったものもありましたが,状況に合わせて使用すれば速くなりそうですね.実際に使ってみるのもいいですね!
プログラミングを知らない人も,Pythonを知らない人も,少しでもPythonに興味をもってもらえれば幸いです.
最後まで読んでくれた方、ありがとうございました!!
[*1] C言語とは古くからあるプログラミング言語です.それの拡張版に当たるのがC++でこれからJava,C#などの言語が作られています.PythonはC言語で作られています.
[*2] コンパイルとは書かれたコードを機械語に翻訳することです.インタプリタ型言語では一行ずつ翻訳してくれるのに対して,コンパイル型言語ではコンパイルという過程によりいっきに翻訳されます.これが速度にも関わってくるのです.
[*3] JITとはコンパイル技術の一種でJava(プログラミング言語)などで採用されています.コンパイル後の速度は速くなりますが実行開始までが遅いという問題があります.
[*4] デコレータとは関数の定義の前で@mf
(mfには任意の関数名)とすることで,その関数に直接書き換えずに機能を編集できる機能らしいです.簡単に言うとある関数を実行してからある関数を実行するみたいな感じです(余計にわからなくなった!?.たとえば関数funcと関数mfがあるとします.関数mfの定義の前で@func
と書いたとすると,ずばりfunc(mf())
と同じことになります.)説明難しい...
[*5] CコンパイラとはC言語やC++で書かれた.c
ファイルをコンパイルして実行形式の.exe
ファイルにします.この処理は書かれたコードを一気に機械語に翻訳します.主にGCCなどのコンパイラやVisual Studioなどの総合開発環境を使うことが多いです.
[*6] Jupyter NotebookとはPythonのコードを対話的に実行できるものでこれを使ってCythonのコードを対話的に実行することができます.使用するにはpip install jupyter
として,起動するにはjupyter notebook
またはipython notebook
とします.※webベースで使用できます
[*7] AtCoderとは競技プログラミングサイトの一つで,プログラミングの速度や技術を競います.