Pythonで2面バッファにロギングしつつ、非同期でファイルに書き出す処理を書いてみた。
Fire-and-forgetとちゅうらしい。いわゆるヤリ逃げされるタスク。
動作仕様
①main()は100msec周期で「日付+ダミーデータ」のCSVデータをバッファに書き込む。
②dataNumMax(100)個データがたまったらファイル書き出し関数(writeDataToFile)を非同期投げっぱなしで呼び出す。
writeDataToFile()は指定されたバッファをファイルに書き出す。
③main()はバッファの書き出し面を切り替える。
※ctrl-Cで抜けてください
※Python3.11です
非同期で動いていることの確認に、writeDataToFile()にsleep()を入れてみる。
main()がバッファに書いている時間には影響しないことがわかる。
ポイント
・非同期処理したい関数にはasyncなどの接頭辞は不要
・非同期で実行するAPIは
loop.run_in_executor(executor, func, *args)
なので関数引数は3つ目の引数に入れる。
asyncio_filewrite.py
import datetime
import asyncio
from time import sleep
# グローバルな2面のデータバッファ
DataBuffer1 = []
DataBuffer2 = []
# ログファイル出力数
logFileNum = 0
# 1ファイルあたりのデータ数
dataNumMax = 100
# 仮のファイル名
MACAddress = "12:34:56:78"
# 2面のデータバッファを指定してバッファ格納
def storeDataBuffer(buffNo, dataStr):
if (buffNo == 0):
DataBuffer1.append(dataStr)
else:
DataBuffer2.append(dataStr)
# 非同期で動かすがasyncは付けない
def writeDataToFile(targetBuffNo):
print("start writeDataToFile" + str(targetBuffNo))
# 例えばここにsleepを入れてもmain側はブロッキングされない(ログファイル上はつながる)
# sleep(1)
devName = MACAddress.replace(":", "")
global logFileNum
filename = devName + "-" + str(logFileNum) + ".csv"
# 指定バッファをファイル書き込み
f = open(filename, "w")
if (targetBuffNo == 0):
f.writelines(DataBuffer1)
DataBuffer1.clear()
else:
f.writelines(DataBuffer2)
DataBuffer2.clear()
f.close()
# ログファイル数を増やす
logFileNum = logFileNum + 1
print("finish writeDataToFile" + str(targetBuffNo))
# メイン関数
def main():
print("start main.")
dataNum = 0
buffNo = 0
while True:
# 100ミリ秒待つ
sleep(0.1)
# 日付情報とダミーデータでCSVのデータを作る
dt_now = datetime.datetime.now()
timestr = dt_now.strftime('%H:%M:%S.%f')
testDataStr = timestr + ",123,456,789\n"
storeDataBuffer(buffNo, testDataStr)
dataNum = dataNum + 1
# データ数が1ファイル分たまったら書き出し
if (dataNum >= dataNumMax):
# ファイルへ非同期で書き出す。関数の引数は3番目に
loop = asyncio.get_event_loop()
loop.run_in_executor(None, writeDataToFile, buffNo) # 投げっぱなし. fire and forget.
print("main() called writeDataToFile().")
# バッファの切り替え(書き込み面を保護するため2面トグル)
dataNum = 0
if (buffNo == 0):
buffNo = 1
else:
buffNo = 0
if __name__ == '__main__':
main()
雑念が多いのでシンプルに非同期のところだけ
asyncio.py
import asyncio
from time import sleep
# 非同期で動かす関数
def writeDataToFile(arg1):
sleep(arg1)
# メイン関数
def main():
while True:
# ループ処理
# 非同期で呼び出す
loop.run_in_executor(None, writeDataToFile, 1)
# すぐ抜けてくる
if __name__ == '__main__':
main()