切掛
Pythonの非同期実行のネタは似たようなもの(公式の翻訳/再編集?)が多かった。
頭が固くなったオジサンには厳しいので、実例を探して複数言語のサイト見て、試行錯誤してやっと動いたので、肝だけを纏めてみた。
概要
例は全部Windowsで外部コマンド実行のパターン
解説はほぼなし。
PIDでチェック
簡単でいいね。オジサンがパッと思いついて作ったのがこれ。
pid.py
import subprocess
from time import sleep
procs = {}
for h in servers:
p = subprocess.Popen(["some", "command"], ...)
# subprocess.runでstdout=PIPEでも動きそうだが未調査
procs[p.pid] = p
while procs:
for pid in list(procs):
if procs[pid].poll in not None:
del procs[pid]
sleep(x)
procsは端からpのlistにしておいてもいいけど、
このやり方だと最後に空になるのがお気に入り。
並列1(STDOUT不要)
実行する対象が何かを生成してくれる場合はこれでOK。
run関数が非同期実行対象。
最初に作ったときはrun_until_completeで呼び出すからcreate_subprocess_shellだけで待ってくれるのかと思っていた。
async1.py
import asyncio
from asyncoio.subprocess import DEVNULL
async def run(param):
# 以下2つどっちでも動く
p = await asyncio.create_subprocess_exec(*["some", "command", param],
stdout=DEVNULL, ...)
p = await asyncio.create_subprocess_shell("some command %s" % param,
stdout=DEVNULL, ...)
await p.wait()
if sys.platform.startswith('win'):
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
funcs = asyncio.gather(*[run(p) for p in parameters])
loop.run_until_complete(funcs)
並列2(STDOUT必要)
実行対象の標準出力を利用して何かをする場合はこっち。
ただし結果はmainのretに終了順に返ってくるので、それに耐えられないと駄目。
async_stdout.py
import asyncio
from asyncoio.subprocess import PIPE
import sys
async def run(param):
p = await asyncio.create_subprocess_shell("some command %s" param,
stdout=PIPE, ...)
return await (p.communicate())[0].decode('code').splitlines()
async def main():
funcs = asyncio.gather(*[run(p) for p in parameters]*)
for f in asyncio.as_completed(funcs):
ret = await f
if sys.platform.startswith('win'):
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
備考
なんか似たようなことばかり書いている気がする。
次はopenpyxlのことでも書くか。