Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

C言語でpythonモジュール作成

突然ですが、pythonって便利ですよね?
f:id:Elsammit:20200530194025j:plain

組込系やWeb系、アプリケーション、機械学習(ディープラーニング)に至るまで幅広く用いることが出来る!!
万能言語ですね!!下回りから上位までを網羅できる!!
ゆりかごから墓場まで!!安心感がすごいです!!。

ただ、、、実は自分、、、あまり好きな言語ではなんですよね。。。
だってだって、処理が遅いんだもん~~~~~!!
分かってるよ、、、分かってますとも。インタプリタ型言語だしね。
だけど、繰り返し処理を実行するだけで数秒掛かる時があるとか、酷い(泣)。
色々なライブラリが提供されており、これらを組み合わせればよいのだろうけど、自分で本当にやりたい処理に対して遠回りしなきゃならない時があったり。。。(泣)

。。。!?
自分で作ればよくない!?自分で作れるならそっちの方が自由度高くかつ高速処理可能なモノが作れね?www
ということで、C言語pythonモジュールを作成してみました!!
今回は、バブルソートpythonモジュールで書いてみます。
一部ソースコードに誤りがありました!!申し訳ございません。。。
うまく配列をC言語モジュールに渡せていないことが原因です。以下は別に作成した簡単なソースコードで確認します。

環境はラズパイ4を用います。

下記を参考に作成してみました。
qiita.com


まず、C言語pythonモジュールの流れですが、
 ①C言語pythonモジュールを作成
 ②ビルド環境作成
 ③pythonC言語をビルド
 ④pythonで生成物をimport
となります。

まず、"①C言語pythonモジュールを作成"です。
全体はこの通りです。

static PyObject* queue(PyObject *self,PyObject *args){
    int x,y,g;
    if (!PyArg_ParseTuple(args, "ii", &x, &y)){
        return NULL;
    }
    g = 0;
    for(int i=0;i<100;i++){
        for(int j=0;j<100;j++){
            if(i%2==0 && j%2==0){
                g = g - i -j;
            }else if(i%2==0 && j%2==1){
                g = g -i + j;
            }else if(i%2==1 && j%2==0){
                g = g + i - j;
            }else{
                g = g + i + j;
            }
        }
    }
    return Py_BuildValue("i",g);
}

static PyMethodDef PracticeMethods[] = {
    {"queue", (PyCFunction)queue, METH_O, "c_test: queue"},
    {NULL,NULL,0,NULL}
};

static struct PyModuleDef practicetmodule ={
    PyModuleDef_HEAD_INIT,
    "c_test",
    NULL,
    -1,
    PracticeMethods
};

PyMODINIT_FUNC PyInit_practice(void){
    return PyModule_Create(&practicetmodule);
}

queue関数は実際にやらせたい処理になります。
残りの処理でqueue関数をモジュールとして、登録処理を実施しています。

次にpythonでビルドするために、setup.pyを作成します。
setup.pyは下記の通りになります。
ここは、参考にさせていただいたソースコードを持ってきて、
対象となるc言語のファイル名だけ変更しました。

from distutils.core import setup, Extension
setup(name='practice',
        version='1.0',
        ext_modules=[Extension('practice', ['c_test.c'])]
)

setup.pyでC言語pythonモジュールにするため、下記でビルドしました。

python setup.py build_ext -i

では実際にpythonでモジュールを利用してみたいと思います。
今回pythonで書いた処理とCモジュールを用いた処理で比較するために、
このようなソースを作成。

import practice as c_practice
import time

start = time.time()
print(c_practice.queue(0,0)) #C言語モジュールの実行.
elapsed_time = time.time() - start
start2 = time.time()
g = 0
#pythonコードの実行.
for i in range(100):
    for j in range(100):
        if i % 2 == 0 and j % 2==0:
            g = g -i - j
        elif i % 2 ==0 and j % 2==1:
            g = g - i+ j
        elif i % 2 == 1 and j % 2==0:
            g = g + i -j
        else:
            g = g + i + j
elapsed_time2 = time.time() - start2

print("C import time is {0}".format(elapsed_time)+"[sec]")
print("python time is {0}".format(elapsed_time2)+"[sec]")

こちらで作成したpythonモジュールを呼び出し、

import practice as c_practice

こちらで実行。

test_list = c_practice.queue(arry)   #c言語のモジュールで実行した場合.

では最後に比較してみます!!
結果はこの通り!!
時間は、各要素数(i,j)毎に5回実施してその平均値となります。
f:id:Elsammit:20200531092704j:plain

pythonコードはやはり遅いですね。。。w
素数(i,j)が5000だと30秒近くかかっている。。。
一方、C言語モジュールを用いた場合には要素数が5000であっても600ms程度で終了します。
モジュール化すると段違いで処理が早くなりますね!!
もしpythonで処理が重い場合にはモジュール化を実施してみるとよさそうです!!
python嫌いな理由が一つ解消しましたww。

追伸:
バブルソートについてはまたどこかでチャレンジしたいと思っております。
実はこのブログを読んだ友達がおかしなことに気づき、連絡頂いたことが原因で発覚しました!!
持つべきものは友達ですね!!

後、要素数10000でpythonコードだと110秒(2分弱)以上かかってましたw。