Blow Up by Black Swan

Python- 一定間隔ごとのプログラムの実行

今回、一定間隔ごと(10秒ごと、1分ごと)にプログラムを実行するコードを書こうとしてかなり悪戦苦闘したので、それをブログ記事にしようと思います。もともと作ろうとしていたのは、複数の仮想通貨取引所のAPIから仮想通貨の売買価格をとって、それをJSONなり、DBなりに保存しようとするものです。timeモジュールのtime.sleep関数を使えば楽じゃないかと思いますが、これを使うと「プログラミング時間+スリープ時間(time.sleep関数で指定した時間)」で実行されていくため、厳密な間隔での実行になりきらないという問題点があります。この問題を解決するのに、意外に時間がかかったというところです。で、この問題の解法として、今回threadingモジュールを利用しました。コードは以下になります。

import time, threading

def timekeep():    #インターバル用関数
    time.sleep(5)

def func1():    #実行したい関数①
    current_time = time.time()
    print('func1')

def func2():    #実行したい関数②
    current_time = time.time()
    print('func2')

funcs = [timekeep, func1, func2]    #実行したい関数の集合
threads = []

current_time = time.time()
for i in range(1, 6):
    for func in funcs:
        t = threading.Thread(target=func)
        t.start()
        threads.append(t)

    for t in threads:
        t.join()

    print(str(i) + '回目: ' + str(time.time() - current_time))

threadingモジュールは、複数の関数や処理を「並列」して行うことができるようにするモジュールです。このthreadingモジュールで以下の3つの関数を並列で実行しています。

関数①: timekeep関数
関数②: func1関数
関数③: func2関数

そして、threding.join()関数とtimekeep関数を用いて、timekeep関数の処理が完了するまで、つまり指定した時間が経過するまで他の関数(func1関数とfunc2関数)は次のループ処理へと進みません。また、timekeep関数を一番最初に実行する関数に指定しておくことで、他の関数の実行時間が合間に入ってくることも避けています。実行結果は以下になります。

func1
func2
1回目: 5.005943059921265
func1
func2
2回目: 10.008951187133789
func1func2

3回目: 15.011608123779297
func1
func2
4回目: 20.017914295196533
func1
func2
5回目: 25.020419120788574

APIから定期的に情報を取るコードを現在作成中なので、また改めて書こうと思います。主要参考サイトは以下になります。読んでくださった方、ありがとうございました。