pythonで周期関数処理（複数スレッド対応）する

#はじめに
周期処理する必要が出たので備忘録を兼ねて
使い方があっている自信はない
最大スレッド数の制限とかしてない

#コード
##周期処理したい関数
```python
#こいつ（処理に３秒かかる）を定期実行する
#処理の想定であるsleepの前後でtimeを吐き出させる

import time

def job():
    job.cnt += 1
    cnt = job.cnt
    print(cnt,"job start", "time:{0}".format(time.time()) + "[sec]")
    time.sleep(3)
    print(cnt,"job end", "time:{0}".format(time.time()) + "[sec]")
```
##スケジューラー
処理時間 > インターバルの場合には、前の処理が終わるまでthreading.Eventでwaitする

```python
import threading
import time

class Scheduler(threading.Timer):
    def __init__(self, interval, function, args=[], kwargs={}, multi_thread=False):
        threading.Timer.__init__(self, interval, self.run, args, kwargs)
        self.function = function
        self.multi_thread = multi_thread
        self.thread = None
        self.prev_thread = None
        self.stop_signal = False
        self.e = threading.Event()
        self.e.set()
        
        #出力用
        self.repeat_cnt = 0
        
    def run(self):
        #出力用
        self.repeat_cnt += 1
        print(self.repeat_cnt,"thread waiting...", "\t", "time:{0}".format(time.time()) + "[sec]")
        
        #複数実行禁止の場合、event setを待つ
        if(self.multi_thread is False):
            self.e.wait()
            self.e.clear()
        #次スレッド作成（停止信号が来てなければ作成）
        if(self.stop_signal is False):
            self.prev_thread = self.thread
            self.thread=threading.Timer(self.interval,self.run)
            self.thread.start()
        #関数実行
        self.function()
        #event set
        self.e.set()
        
    def stop(self):
        if self.thread is not None:
            self.stop_signal = True
            self.thread.cancel()
            self.prev_thread.join()
            self.thread = None
```

#実行例
##複数スレッド許可
スレッドの作成は0,2,4秒の時に行われるので、３回実行される

```python
job.cnt = 0

scheduler = Scheduler(2, job, multi_thread = False)
print("START","time:{0}".format(time.time()) + "[sec]")
scheduler.start()
time.sleep(4.5)
print("STOP","time:{0}".format(time.time()) + "[sec]")
scheduler.stop()
print("Done.","time:{0}".format(time.time()) + "[sec]")
```
###結果
スレッド１の終了を待たず、スレッド２の作成、開始が行われている

```
START 			 time:1524085228.4630785[sec]
1 thread waiting... 	 time:1524085228.4721122[sec]
1 job start 		 time:1524085228.4729774[sec]
2 thread waiting... 	 time:1524085230.4730806[sec]
2 job start 		 time:1524085230.4734263[sec]
1 job end 		 time:1524085231.475667[sec]
3 thread waiting... 	 time:1524085232.4734714[sec]
3 job start 		 time:1524085232.4741168[sec]
STOP 			 time:1524085232.9767313[sec]
2 job end 		 time:1524085233.4753876[sec]
3 job end 		 time:1524085235.475587[sec]
Done. 			 time:1524085235.4762127[sec]
```
##複数スレッド不可
スレッドの開始は0,3秒の時に行われるので、２回実行される

```python
job.cnt = 0

scheduler = Scheduler(2, job, multi_thread = False)
print("START","\t\t\t","time:{0}".format(time.time()) + "[sec]")
scheduler.start()
time.sleep(4.5)
print("STOP","\t\t\t","time:{0}".format(time.time()) + "[sec]")
scheduler.stop()
print("Done.","\t\t\t","time:{0}".format(time.time()) + "[sec]")
```
###結果
スレッド１の終了を待たずにスレッド２が作成されているが、スレッド１が終了するまで開始はされない

```
START 			 time:1524085395.7251694[sec]
1 thread waiting... 	 time:1524085395.7262063[sec]
1 job start 		 time:1524085395.7279484[sec]
2 thread waiting... 	 time:1524085397.7280304[sec]
1 job end 		 time:1524085398.7284186[sec]
2 job start 		 time:1524085398.72894[sec]
STOP 			 time:1524085400.2278214[sec]
2 job end 		 time:1524085401.7318819[sec]
Done. 			 time:1524085401.7322009[sec]
```
#参考文献
[Pythonのthreading.Timerで定期的に処理を呼び出すサンプル](https://ja.stackoverflow.com/questions/24508/python%E3%81%AEthreading-timer%E3%81%A7%E5%AE%9A%E6%9C%9F%E7%9A%84%E3%81%AB%E5%87%A6%E7%90%86%E3%82%92%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%99%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB)
[おまいらのthreading.Eventの使い方は間違っている](https://qiita.com/tag1216/items/2dcb112f8018eb19a999)