Cucco’s Compute Hack

コンピュータ関係の記事を書いていきます。

時刻ちょうどに実行する その3

5秒に1回のタスクAと、15秒に1回のタスクBがある。
タスク自体は、マルチプロセスで動く。
タスクの実行中は、メインプロセスはある作業を実施できない。
タスクAまたはタスクBを実行した場合は、メインタスクを1回だけ実行する。

import multiprocessing
import datetime
import time

class Worker(multiprocessing.Process):
	def __init__(self,t,workload=2):
		self.t=t
		self.workload=workload
		super(Worker, self).__init__()
	
	def run(self):
		#print(self.name,self.t)
		time.sleep(self.workload)
		return

def uctdatetime00sec(pattern=None):
	"""
	秒以下が0のdatetimeを返す。
	pattern="future"の場合は、直近の未来の時刻を返す。
	"""
	time_now=datetime.datetime.utcnow()
	if pattern=="future":
		time_offset=datetime.timedelta(minutes=1) # 1分先にずらしておく。
		time_now=time_now + time_offset
		
	time_now=datetime.datetime(time_now.year, time_now.month, time_now.day, time_now.hour, time_now.minute, second=0, microsecond=0, tzinfo=None)
	
	return time_now

if __name__ == '__main__':
	taskA=None
	taskB=None
	run_main_task=False

	#仮の時刻
	time_now=datetime.datetime.utcnow()
	
	time_offset=datetime.timedelta(seconds=60) #繰り返しの間隔(秒)
	
	time_offset_taskA = datetime.timedelta(seconds=5) #繰り返しの間隔(秒)
	time_offset_taskB = datetime.timedelta(seconds=15) #繰り返しの間隔(秒)
	
	time_done_taskA=time_now
	time_done_taskB=time_now
	
	print(time_now)
	
	#0秒ちょうどの時刻から開始。
	time_now=uctdatetime00sec(pattern="future")
	
	time_next_taskA=time_now + time_offset_taskA
	time_next_taskB=time_now + time_offset_taskB
	
	print("demo wills start at ", time_now)
	
	time_end=time_now + time_offset
	
	while time_end > datetime.datetime.utcnow():#デモプログラムなので1分で終わらせる。
		
		time_now=datetime.datetime.utcnow()
		
		if time_now >= time_next_taskA:
			time_next_taskA=time_now + time_offset_taskA
			while time_now > time_next_taskA:
				print("skip taskA")
				time_next_taskA=time_now + time_offset_taskA
				
			#5秒に1回のタスクをここに記述(非同期)
			taskA=Worker(time_now,workload=1) # startは2回呼べないのでオブジェクトを作りなおし
			taskA.start()
			print("taskA start",time_now)
			run_main_task=True
			
		if time_now >= time_next_taskB:
			time_next_taskB=time_now + time_offset_taskB
			while time_now > time_next_taskB:
				print("skip taskB")
				time_next_taskB=time_now + time_offset_taskB
				
			time_next_taskB=time_now + time_offset_taskB
			#15秒に1回のタスクをここに記述(非同期)
			taskB=Worker(time_now,workload=1) # startは2回呼べないのでオブジェクトを作りなおし
			taskB.start()
			print("taskB start",time_now)
			run_main_task=True
		
		#全部のタスクが終わるのを待つ
		#動いていないタスクは待てない。。。
		#ifの評価は左の論理が優先。
		if (taskA is not None) and (taskA.is_alive()):
			taskA.join()
		if (taskB is not None) and (taskB.is_alive()):
			taskB.join()
		
		if run_main_task==True:
			print("main task",datetime.datetime.utcnow())
			#変更後に1回メインタスクを実行したので次の変更まで何もしない。
			run_main_task=False
		
	print("end")

実行結果

C:\>python C:\multiProcessTest2.py
2018-03-16 14:13:07.936899
demo wills start at  2018-03-16 14:14:00
taskA start 2018-03-16 14:14:05.000162
main task 2018-03-16 14:14:06.433244
taskA start 2018-03-16 14:14:10.000448
main task 2018-03-16 14:14:11.359526
taskA start 2018-03-16 14:14:15.000734
taskB start 2018-03-16 14:14:15.000734
main task 2018-03-16 14:14:16.387814
taskA start 2018-03-16 14:14:20.001020
main task 2018-03-16 14:14:21.356098
taskA start 2018-03-16 14:14:25.001306
main task 2018-03-16 14:14:26.358384
taskA start 2018-03-16 14:14:30.001592
taskB start 2018-03-16 14:14:30.001592
main task 2018-03-16 14:14:31.419673
taskA start 2018-03-16 14:14:35.001878
main task 2018-03-16 14:14:36.352956
taskA start 2018-03-16 14:14:40.002164
main task 2018-03-16 14:14:41.358242
taskA start 2018-03-16 14:14:45.002450
taskB start 2018-03-16 14:14:45.002450
main task 2018-03-16 14:14:46.407531
taskA start 2018-03-16 14:14:50.002736
main task 2018-03-16 14:14:51.363814
taskA start 2018-03-16 14:14:55.003022
main task 2018-03-16 14:14:56.368100
end