コルーチンの試用
コルーチンを使用してみた。備忘録として以下に記す。スクリプトは圧縮ファイルscriptfile.zipとして纏めた。ダウンロードして自由に利用されたい。
並列にプログラムを実行する方法としては、マルチプロセスで平行に同時に実行して計算時間を短縮する方法があるが、これについては別のウェブサイトで取り上げた。
コルーチンは順番に実行されるので、全体の計算時間は短縮されないが、複数の処理を並行して行うときに便利である。コルーチンでは、グローバル変数を用いて、コルーチン間の連携が簡単にできる。以下の例(リスト1)では、押されたキーに応じて、2つの時計の動作が制御されている。キー押しをチェックするコルーチン1つと2つの時計のコルーチン2つの計3つのコルーチンが2つのグローバル変数flgsとck_stateによって連携されている。
リスト1のスクリプトでは、以下のコードによって、3つのコルーチンを登録している。
ensure_future(check_key()) # check_key()実行のスケジュール
ensure_future(myclock(1)) # myclock(1)実行のスケジュール
ensure_future(myclock(2)) # myclock(2)実行のスケジュール
次のコードによって、3つの関数がコルーチンとして順番に並行して実行される。
loop.run_forever()
コルーチンの実行が始まると、myclock(1)とmyclock(2)により2つの時計が表示される。2つの時計が重なっているが、これはドラッグして見やすくすればよい。
図1
実行開始時は「休憩中」と表示されている。この表示状態は、check_key()によってコントロールされている。
async def check_key():
"""
押されたキーに応じて時計の状態を設定
"""
global ck_state
flgs['ck'] = False
while True:
if
keyboard.is_pressed('q'): # このコルーチンの終了
break
if
keyboard.is_pressed('0'): # すべての時計を邱氏
ck_state = 0
if
keyboard.is_pressed('1'): #
時計1を動かす
ck_state = 1
if
keyboard.is_pressed('2'): #
時計2を動かす
ck_state = 2
if
keyboard.is_pressed('3'): #
すべての時計を動かす
ck_state = 3
await sleep(0)
# 他のコルーチンへ実行を移す
flgs['ck'] = True # このコルーチンの終了を記録
Check_CRs()
# すべてのコルーチンの終了をチェック
キー「q」を押せば、プログラムの実行終了となり、キー「1」、キー「2」を押せば、時計1、時計2が動く。キー「3」を押せば、2つの時計が動く。
これは、async def myclock(id)内の以下のコードにより制御されている。
while True:
if
ck_state in set([id, 3]):
# 時刻の表示
now = datetime.now()
s = '{0:0>2d}:{1:0>2d}:{2:0>2d}'.format(
now.hour, now.minute, now.second)
cnvs.itemconfig('MyText', text = s)
else:
# 休憩の表示
cnvs.itemconfig('MyText', text = '休憩中')
cnvs.update()
if
flgs['ck'] == True:
# このプログラムの終了をチェック
flgs[id] = True
# このコルーチンの終了を記録
break
await sleep(0)
# 他のコルーチンへ実行を移す
キー「1」を押すと、時計1が動く(図2)。
図2
キー「2」を押すと、時計2が動く(図3)。
図3
キー「3」を押すと、2つの時計が動く(図4)。
図4
キー「0」を押すと、2つの時計は休止する(図5)。
図5
キー「q」を押せば、プログラムの実行終了である。
from asyncio import *
import keyboard
import tkinter as tk
from datetime import datetime
flgs = {}
# コルーチンの状態
ck_state = 0 # 時計の状態
def Check_CRs():
"""
コルーチンのチェック
"""
ck_end = True
vals = flgs.values()
for val in vals:
if
val == False:
ck_end = False
if ck_end:
# すべてのコルーチンが終了しておれば実行
loop.stop()
# イベントループのストップ
async def check_key():
"""
押されたキーに応じて時計の状態を設定
"""
global ck_state
flgs['ck'] = False
while True:
if
keyboard.is_pressed('q'): # このコルーチンの終了
break
if
keyboard.is_pressed('0'): # すべての時計を邱氏
ck_state = 0
if
keyboard.is_pressed('1'): #
時計1を動かす
ck_state = 1
if
keyboard.is_pressed('2'): #
時計2を動かす
ck_state = 2
if
keyboard.is_pressed('3'): #
すべての時計を動かす
ck_state = 3
await sleep(0)
# 他のコルーチンへ実行を移す
flgs['ck'] = True # このコルーチンの終了を記録
Check_CRs()
# すべてのコルーチンの終了をチェック
async def myclock(id):
global ck_state
flgs[id] = False
root = tk.Tk()
root.title(f'Clock-{id}')
cnvs = tk.Canvas(root, width
= 500, height = 200, background = '#00ffff')
cnvs.pack()
cnvs.create_text(250, 100,
text = '', font = ('', 50), fill = 'blue',
tags = 'MyText')
while True:
if
ck_state in set([id, 3]):
# 時刻の表示
now = datetime.now()
s = '{0:0>2d}:{1:0>2d}:{2:0>2d}'.format(
now.hour, now.minute, now.second)
cnvs.itemconfig('MyText', text = s)
else:
# 休憩の表示
cnvs.itemconfig('MyText', text = '休憩中')
cnvs.update()
if
flgs['ck'] == True:
# このプログラムの終了をチェック
flgs[id] = True
# このコルーチンの終了を記録
break
await sleep(0)
# 他のコルーチンへ実行を移す
Check_CRs()
# すべてのコルーチンの終了チェック
root.destroy()
loop = get_event_loop()
ensure_future(check_key()) # check_key()実行のスケジュール
ensure_future(myclock(1)) # myclock(1)実行のスケジュール
ensure_future(myclock(2)) # myclock(2)実行のスケジュール
try:
loop.run_forever()
# イベントループをstop()が呼び出されるまで実行し続ける
finally:
loop.close()
# イベントループを閉じる