å±±æ¬æ³°å®ã§ããããã«ã¡ã¯ã
éç¨æ¬é¨ã§ã¯æè¿ Python3 ã¸ã®ç§»è¡ãé²ãã¦ãã¾ãããã¡ãã®è©±ã¯å¥éãç´¹ä»ããäºå®ã§ãããä»å㯠Python3.4 ã§è¿½å ããã asyncio ã¢ã¸ã¥ã¼ã«ã®ä½¿ããã(ã¨ãããè½ãç©´)ã解説ãã¾ããå ã«çµè«ãæ¸ãã¦ããã¨ãPython3.5 ã®æ¹è¯ãå¾ ã¤ã®ãåã¨ãã話ã§ãã
ãµã³ãã«ã¨ãã¦è¤æ°ã® SSH ãä¸æã«å¼ã³åºãã¦ãã¾ããã¨å¦çãã¦ããã passh ã GitHub ã§å ¬éãã¦ãã¾ããå®éã«ç¤¾å ã§å©ç¨ãã¦ãããã®ãããã¥ã¼ã³ãã¦ä½¿ããããã¾ã¨ãããã®ã§ãã
æ¬é¡ã® asyncio ã§ãããPython3 ã§éåæ I/O å¦çãå®ç¾ããããã«è¿½å ãããã¤ãã³ãé§åå¦çã®ãã¬ã¼ã ã¯ã¼ã¯ã§ããæåã«æ¸ãã¦ããã¾ããã以ä¸ã§è¨åããé£ãããªç¹ã®ããã¤ã㯠Python3.5 ã§æ¹è¯ãããäºå®ã®ããã§ãã[PEP-0492, PEP 492 vs. PEP 3152, new round]
1. asyncio 㯠Python ã®ä¸ã®ç¬èªä¸ç
è¨èªãã¤ãã£ãã«éåæå¦çãå®è£
ããã¦ãã Go ã®ãããªè¨èªã¨éããã©ã¤ãã©ãªã¨ãã¦å¾ä»ãããã¦ããããé常㮠Python ã®æ¸ãæ¹ãã§ãã¾ãããä¾ãã°åããã»ã¹ã®å¦çã« subprocess
ã使ãã¨åæ I/O ã«ãªã£ã¦ãã¾ãã¾ããasyncio æµã®æ¸ãæ¹ãããªããã°ãããªãã®ã§ãPython ã«ç¿çãã¦ãã人ã§ãå¦ç¿ã³ã¹ããé«ãã§ãã
å®éã18.5 asyncio ã®ç®æ¬¡ãè¦ãã ãã§ãæ¯ãã®ã§ã¯ãªãã§ãããããåé ã«æ¸ããã¦ãã¾ãããAPI ã¯ã¾ã å®å®ãã¦ããã¨ã¯è¨ãããããPython3.4.4 ã Python3.5 ã§å¤æ´ãããäºå®ã§ãã
2. ã³ã«ã¼ãã³ã¯ generator
asyncio ã§ã¯ã³ã«ã¼ãã³(coroutine, å調çãã«ãã¿ã¹ã¯ã®ä»çµã¿)ã¨ããæ¦å¿µãå°å
¥ããã¦ãã¾ããå
¬å¼ãªè§£èª¬ãèªãã§ãè¯ãããããªãã¨æãã¾ãããéè¦ãªã®ã¯åé ã® "A coroutine is a generator" ã§ããä»ãå ãããªã yield from
ã§ãµãã® generator ã«å¦çã移è²ãããã¨ãå¤ã(å¿
é ã§ã¯ãªã) generator ã§ãã
yield from
ãå«ã¾ããé¢æ°ãã¡ã½ããã¯æé»çã« generator ã«ãªãã®ã§ãæ®éã«å¼ã³åºãã¦ãæ¬ä½ãå®è¡ããã¾ãããä¾ãã°ä»¥ä¸ã®ã³ã¼ããããã¨ãã¾ãã
def B(): ... @asyncio.coroutine def A(): B()
B ãæ®éã®é¢æ°ã§ããã°åé¡ãªã A ãã B ã®å¦çãå¼ã³åºããã¾ããããããã¨ã B ã®ä¸ã§ã¹ãªã¼ãããå¦çã追å ããã¨ãã¾ãã
def B(): ... yield from asyncio.sleep(1) ...
ãã®å¤æ´ãå ããã¨ãA ãã B ã®å¦çã¯å¼ã³åºãããªããªã£ã¦ãã¾ãã¾ããyield from
ããã㨠B 㯠generator ã«ãªã£ã¦ãã¾ãããã§ããB ã« yield from
ãå ããã¨ãå¼ã³åºãå
ã® A ã以ä¸ã®ããã«ä¿®æ£ãå¿
è¦ã«ãªãã¾ãã
@asyncio.coroutine def A(): yield from B()
ããã¯ã¾ãæåã«ã¯ã¾ãç½ ã§ãããªãã¡ã¯ã¿ãªã³ã°ãªã©ã§ãã£ãã yield from
ãå
¥ãã¨ãé常ã®é¢æ°ã generator ã«ãªã£ã¦ãã¾ãããã§ãããããã«ç½ ãããã®ã§ãPEP-0492 ã§æ¹è¯ãäºå®ããã¦ãã¾ãã
3. loop.close()
ã¯å¼ã¶ã¹ãã§ã¯ãªã
å ¬å¼ã®ãµã³ãã«ã³ã¼ãã®ãããã¨ããã§ãæ«å°¾ã«ã¤ãã³ãã«ã¼ããã¯ãã¼ãºããã³ã¼ããåºã¦ãã¾ãã
ããã§ããã°ã©ã ãçµäºããã®ã§ããã°ããã®ã§ãããã©ã¤ãã©ãªçã§ããã°ã©ã ããã®å¾ãç¶ç¶ããå ´åãloop.close()
ãå¼ãã§ã¯ããã¾ãããã¤ãã³ãã«ã¼ãã¯ã¹ã¬ããæ¯ã«èªåçã«ä½ãããããã©ã«ãã®ãã®ãããã®ã§ãããä¸åº¦ã¯ãã¼ãºããã¨ããã®å¾ä½¿ããªããªãã¾ãã
ä¾ãã° passh.PAssh.run()
ããã loop.close()
ãã¦ãããããã®ã¹ã¬ããã§å度 passh.PAssh
ã使ããã¨ããã¨ä¾å¤ãçºçããããã«ãªã£ã¦ãã¾ãã¾ãã
対æ¡ã¨ãã¦ã¯ asyncio.new_event_loop()
ã§ã¹ã¬ããããã©ã«ãã§ã¯ãªãã¤ãã³ãã«ã¼ããä½ã£ã¦ä½¿ããã¨ãèãããã¾ãããå®éã«ããã¨è¨ã®éã§ããasyncio ã¯åæã§æé»çã« Future ã Task ãä½ãã®ã§ããããã®éã«ã¹ã¬ããããã©ã«ãã®ã¤ãã³ãã«ã¼ãã使ããã¦ãã¾ãããã§ããã§ããªãã¯ãªããã©...ã¨ãã£ãã¨ããã§ããããã
4. asyncio.wait
ã®ä¾å¤å¦ç
è¤æ°ã®ã³ã«ã¼ãã³ãå®è¡ãã¦çµæãå¾
ã¤ã¨ããå
¸åçãªå¦çã§ä½¿ãããã®ã asyncio.wait
ã§ãããä¾å¤ã®å¦çã«ç½ ãããã¾ããå
¬å¼ã®ãµã³ãã«ã³ã¼ã ã§ã¯ä¾å¤ãç¹ã«å¦çããã¦ãã¾ãããããããçä¼¼ããã¨ã¤ã³ã¿ããªã¿çµäºæã«ããããä¾å¤ã表示ãããã¨ãã£ããã¨ã«ãªãã¾ãã
import asyncio, sys @asyncio.coroutine def A(): print('hoge', file=sys.stder) # sys.stderr ã®ééã yield True asyncio.get_event_loop().run_until_complete(asyncio.wait([A()])) # ä¾å¤ãé£ã°ãªã
asyncio
ã¯è²ã
ãªç®æã§æé»çã«ã³ã«ã¼ãã³ã asyncio.Future
ã§ããã¿ã¾ããã³ã«ã¼ãã³ã§çºçããä¾å¤ã¯ Future ã«æ ¼ç´ãããå¾ã§ asyncio.Future.result()
ãå¼ã¶ã¨ä¾å¤ãå raise ããã¾ããrun_until_complete
㯠result()
ãæé»çã«å¼ã³åºãã®ã§ã大æµã®å ´åã¯ä¾å¤ãçºçãã¾ãã
ããasyncio.wait
ã¯è¤æ°ã®ã³ã«ã¼ãã³ã® Future ã®éåãè¿ã Future ãè¿ã(not typo)ã®ã§ãåã
ã®ã³ã«ã¼ãã³ã® Future.result()
ã¯å¼ã³åºããã¾ããããã®ããå
¬å¼ã®ãµã³ãã«ã³ã¼ãéãã ã¨ä¾å¤ãçºçãããã¤ã³ã¿ããªã¿ãæãã段ã§ãããããã¹ãã©ã¯ã¿å¦çãä½åãã¦æ°ä»ãã¨ããããã§ãã
async.wait
ã使ç¨ããã³ã¼ããç¡äºåããããã«è¦ãã¦ããå®ã¯ä¾å¤ãçºçãã¦ä½ãå¦çããã¦ããªãããããã¾ãããæ£ããã¯ä»¥ä¸ã®ããã«å¦çãã¾ãã
done, _ = asyncio.get_event_loop().run_until_complete(asyncio.wait([A()])) for future in done: future.result() # ä¾å¤ãããã° raise ãã
5. æåã®ä¾å¤ã§æ¢ããã
åè¿°ã®ããã« asyncio.wait
ã¯ä¾å¤ãçºçãã¦ãå
¨é¨ã®ã³ã«ã¼ãã³ãå®è¡ãã¾ããéåæå¦çã§ã·ã³ã°ã«ã¹ã¬ãããªã®ã§ããããæåã®ä¾å¤ã§æ¢ãããã§ããã
ããæãã¤ã loop.stop()
ã¯ç¢ºãã«ã¤ãã³ãã«ã¼ããæ¢ãã¾ãããæ¢ããã³ã«ã¼ãã³ãã´ãã¨ãã¦æ®ã£ã¦ãã¾ããã¨ã©ã¼å¦çå¾ã«å度ã¤ãã³ãã«ã¼ãã使ããã¨ããã¨ã¨ã©ã¼ã«ãªã£ã¦ãã¾ãã¾ãã
æ£ããæ¹æ³ã¯ã以ä¸ã®ããã«ãã£ã³ã»ã«ãããã¨ã§ãã
@asyncio.coroutine def A(): try: ... except Exception as e: ... for task in asyncio.Task.all_tasks(): task.cancel()
ã¿ã¹ã¯ããã£ã³ã»ã«ããã¨ãrun_until_complete
㯠asyncio.CancelledError
ãæããã®ã§ã注æãã¦ãã ããã
ã¾ã¨ã
以ä¸ã®ãããªç½ ã«ã¯ã¾ããªããä½ã£ãã®ã passh ã§ãã注æç¹ã annotate ãã¦ããã¾ãã®ã§ãåèã«ãªãã°å¹¸ãã§ãã
使ã£ã¦ã¿ãææã¨ãã¦ã¯ãasyncio ã使ããããã° Python3.5 ãå¾ ã¤ã®ãè¯ãã®ã§ã¯ãªããã¨æãã¾ããã以åæèªã®ããã«èªä½ã®ã¤ãã³ãé§åãã¬ã¼ã ã¯ã¼ã¯ãä½ã£ãã®ã§ãããèªä½ããããå°ã楽ã¯ã§ãã¾ãã