35
51

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonで非同期投げっぱなしファイル書き出し

Last updated at Posted at 2023-01-28

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()
35
51
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
51

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?