倧å€ããŸããããŸããã æ°å¹Žåãããã£ãšæžãæžããšè©æ¬ºããŠãã asycnio ã®èšäºã§ãã
æ¥æ¬èªã®asyncioé¢é£ã®ããã°ãšã³ããªã¯å€§äœèªãã æ°ãããŸãã(è±èªã®èšäºãå°ã)
ãªãã¡ã¬ã³ã¹ãå€ãã®ã§ãããŒãžæ«ã«åèURLããªã³ã¯ããŠãããŸãã詳ããã¯ãã¡ããåç §ãã ããã
- info
asyncio ã¯ãããããªæŠå¿µãåå± ããŠãããåŠç¿ã³ã¹ããé«ãã§ãã
ããªããšãªãããšã¯æžããŸããããå²ãšè©³çŽ°ã«æžããŠããã®ã§æŠèŠã ãç¥ããããšããæ¹ã¯ ãæŠèŠãã»ã¯ã·ã§ã³ã ãèªãã§ãã©ãŠã¶ããã¯ããã»ãããããããããŸãããã¿ã€ãã«è©æ¬ºã§ããã
èªã¿é²ããäžã§ãžã§ãã¬ãŒã¿ã®æŠå¿µãå¿ èŠã§ãã®ã§ãããããªããšããæ¹ã¯å ã«ãã¡ãããã©ããã
[Python] éšå±ãšYã·ã£ããšã€ãã¬ãŒã¿ãšãžã§ãã¬ãŒã¿ãšç§ (äœã ãã®ã¯ãœã¿ãããªã¿ã€ãã«)
ãªãããã®èšäºã§ã¯ Python 3.7 ã䜿ããŸãã 3.7以äžã§ãã䜿ããªãã¡ãœãããããã®ã§ãåçµãããšãã¯ããŒãžã§ã³ã«ã¯æ°ãã€ããŠãã ããã
æŠèŠ
asyncio 㯠Python3.4 ããå°å ¥ããã éåæåŠçãæ±ãããã®æšæºã©ã€ãã©ãªã§ãã
åéãããŠã¯ãããªãã®ã¯ ãããŸã§ã·ã³ã°ã«ã¹ã¬ããäžã§åäœãããã®ã§ã ãã«ãã¹ã¬ããããã«ãããã»ã¹ã®ãããªäžŠè¡åŠçã§ã¯ãªããšããããšã§ãã
GIL ã®å¶éã«ããå®å šã«äžŠåã§ããªããšã¯ããããã«ãã¹ã¬ããã§ã¯å¥ã¹ã¬ããã«å¹²æžããããšãªãåŠçã¯ã»ãŒåæã«äžŠè¡ããŠã€ãé²ãã§ãããŸãã ã³ãŒã«ããã¯é¢æ°ãã°ããŒãã«å€æ°ãªã©ã䜿ã£ãŠåæããããšã¯ã§ããŸãããã¹ã¬ããéã¯ãäºãã®ååšãªããŠç¥ã£ããã£ã¡ããããŸããã
ããã«å¯Ÿã asyncio 㯠åºæ¬çã«ã·ã³ã°ã«ã¹ã¬ããã§åäœããè©Šè¡ããè€æ°ã®åŠç㯠é 次ã«åŠçããã ãããã¯ãŒã¯çã®IOåŸ ã¡æéã«ã¶ã€ãããšå®è¡å¯èœãªå¥ã®åŠçãå®è¡ããããšãã£ãå ·åã«ç¡é§ãªIOåŸ ã¡æéãæå¹æŽ»çšãã¹ããå¥ã®åŠçãå²ãåœãŠãŸãã
gantt title asyncioã®å²åœã€ã¡ãŒãž(åäœã«ç¹å¥ãªæå³ã¯ãªã dateFormat YYYY-MM-DD axisFormat %d section åŠç1 CPUæé :crit, a1, 2000-01-01, 1d IOæé :active, a2, after a1, 3d CPUæé :crit, a3, after c1, 2d IOæé :active, a4, after a3, 4d CPUæé :crit, a5, after a4, 1d section åŠç2 CPUæé :crit, b1, 2000-01-02, 2d IOæé :active, b2, after b1, 2d CPUæé :crit, b3, after a3, 1d IOæé :active, b4, after b3, 4d section åŠç3 CPUæé :crit, c1, 2000-01-04, 2d IOæé :active, c2, after c1, 3d CPUæé :crit, c3, after b3, 2d IOæé :active, c4, after c3, 3d
gantt title ãã®äŸã§ã¯çŽåã«åŠçãããšåãããããã dateFormat YYYY-MM-DD axisFormat %d section åŠç1 CPUæé :crit, a1, 2000-01-01, 1d IOæé :active, a2, after a1, 3d CPUæé :crit, a3, after a2, 2d IOæé :active, a4, after a3, 4d CPUæé :crit, a5, after a4, 1d section åŠç2 CPUæé :crit, b1, after a5, 2d IOæé :active, b2, after b1, 2d CPUæé :crit, b3, after b2, 1d IOæé :active, b4, after b3, 4d section åŠç3 CPUæé :crit, c1, after b4, 2d IOæé :active, c2, after c1, 3d CPUæé :crit, c3, after c2, 2d IOæé :active, c4, after c3, 3d
ã©ã¡ãã®å³ãCPUæéã¯éè€ããŸããããäžã®å³ã¯IOæéãšCPUæéãéãªããã®åãççž®ãããããã§ãã
ãã®ãããasyncio 㯠(åºæ¬çã«) ãããã¯ãŒã¯éä¿¡çã® IOæéãé·ããŠãããã¯ããããããªåŠçã§ã¯ å¹çåã«ãã é«éåãæããŸããã CPUæéãé·ãåŠçã§ã¯å®è¡å®äºãåŸ ã¡ç¶ããããšãšãªãã å¹çåãããªããã é«éåã¯æããŸããã
äž»ãªç»å Žäººç©
ããŠããã㧠asyncio ã䜿ãäžã§éèŠãªæ©èœãèŠãŠããããšã«ããŸãããã
Future
Futureã¯åŠçã®çµæãæ ŒçŽããããã®ãªããžã§ã¯ãã§ãã
JavaScript ã觊ã£ãããšãããæ¹ãªã Promise
ãšããã°ããããããããŸãããã
ãã㯠Future_ãã¿ãŒã³ ãšãã䞊è¡åŠçã«ããããã¶ã€ã³ãã¿ãŒã³ã® asyncio å®è£ ã§ãã
çµæãªããžã§ã¯ãã ããå ã«çæãã åŠçãå®äºãã段éã§çµæãæ ŒçŽããããšã§åŠçãå®äºã¿ã€ãã³ã°ãæ°ã«ããå®è£ ãã§ããŸãã
Future ã«ã¯ ãçµæããšãã¹ããŒã¿ã¹ããšããå±æ§ããããã³ãŒã«ããã¯é¢æ°ãªã©ã䜿ã£ãŠæ瀺çã«æ ŒçŽããŠãããŸãã
ã¹ããŒã¿ã¹ã¯ ãpendingããfinishedããcancelledãã®ïŒçš®é¡ãããã åæç¶æ ã¯ãpendingãã§ãçµäºç¶æ ã¯ãfinishedãããcancelledãã®ããããã§ãã
pending ããçµäºç¶æ ã«ã©ã®ããã«é·ç§»ãããèŠãŠã¿ãŸãããã
- finishedã«ãã
- cancelledã«ãã
ã¹ããŒã¿ã¹ã finished ã«ããã«ã¯ã future.set_result ãšããã¡ãœããã䜿ããŸãã ãã®ã¡ãœããã«ããçµæãæ ŒçŽããããšèªåçã« futureãªããžã§ã¯ãã®ã¹ããŒã¿ã¹ã¯ finished (çµäº) ã«ç§»è¡ããŸãã
å€ãæ ŒçŽããã«ã¹ããŒã¿ã¹ã finished ã«å€ããããšã¯ã§ããªãããã§ãã
ã¹ããŒã¿ã¹ã cancel ã«å€æŽããã«ã¯ future.cancel ãšããã¡ãœããã䜿ããŸãã ããã«ãã futureãªããžã§ã¯ãã®ã¹ããŒã¿ã¹ã¯ cancelled (ãã£ã³ã»ã«) ã«ç§»è¡ããŸãã
å€ãæ ŒçŽããããšã¯ã§ããªãããã§ãã
>>> future = loop.create_future() >>> future.set_result(100) >>> future <Future finished result=100> >>> future.done() True >>> future.cancel() # äžåºŠçµäºããããã£ã³ã»ã«ã¯åºæ¥ãªã False >>> future.cancelled() # ãã£ã³ã»ã«ã«ãªããªã False
>>> future = loop.create_future() >>> future.cancel() True >>> future <Future cancelled> >>> future.done() # ãã£ã³ã»ã«ãäžå¿çµäºãšèšããã®ã§ çãšãªã True >>> future.cancelled() # ãã£ã³ã»ã«ã«ãªã True >>> future.set_result(100) # äžåºŠãã£ã³ã»ã«ãããçµæãæ ŒçŽã§ããªã Traceback (most recent call last): File "<stdin>", line 1, in <module> asyncio.base_futures.InvalidStateError: invalid state
Future ãªããžã§ã¯ãåäœã§ã¯äœãã§ãããšããããã§ã¯ãããŸãããã åŸè¿°ããæ©èœã®äžã§å©çšãããããšã«ãªãã®ã§æåã«èª¬æããŸããã
- warning
- 空ã®Future ãªããžã§ã¯ãã¯
loop
ãªããžã§ã¯ã(åŸè¿°)ã®create_future
ã䜿ã£ãŠçæããããšãæšå¥šãããŠããŸãã - Futureã¯ã©ã¹ãçŽã«è§Šãã®ã¯ãããŸãããã
- 空ã®Future ãªããžã§ã¯ãã¯
- 該åœã³ãŒã
Coroutine
- info
- ããã§èª¬æããã³ã«ãŒãã³ãšã¯ãããŸã§ asyncioå°çšã®ã³ã«ãŒãã³ã§ããã ä»èšèªã®ã³ã«ãŒãã³ã®å®çŸ©ãšå¿ ãããäžèŽãããã®ã§ã¯ãããŸããã
ã³ã«ãŒãã³ã¯ asyncio ã§å®è¡ããåŠçã®ããšã§ãã
ãããŠã³ã«ãŒãã³ã宣èšããããã®æã async
æã§ãã
å°é£ããåèªãåºãŠããŸããããã³ã«ãŒãã³ã®å®æ ã¯æŠããžã§ãã¬ãŒã¿ã§ãã
ãããã ãæŽå²ãããã®ãŒã£ãŠã¿ãŸãã
Python3.3 (PEP380) 㧠yield from
æãšããæ§æãç»å ŽããŸããã
詳ããã¯ãµããžã§ãã¬ãŒã¿ãžã®å§è²ãšèšãããã§ãã(iterableãªããªãã§ãåãä»ãããã§ããããã¯..)
ããŸãæ°ããã®ãåºãŠãã..ããšäžå®ã«æãããããããŸãããããããŸã§èº«æ§ããå¿ èŠã¯ãããŸããã
ããã¥ã¡ã³ãã«ãæžããŠãããšããã yield from iterable
ã¯
for item in iterable: yield item
ãšã»ãŒåãæå³ã§ãã
ã€ãŸããã®æãããé¢æ°ã¯ãžã§ãã¬ãŒã¿ãªã®ã§ãã
ãšã¯ãã圢ã ããèŠããŠãããããã yield from
æã®ããããããæããããšã¯ã§ããªãã§ãããã
éèŠãªã®ã¯ æå®ããããªããžã§ã¯ãã®èŠçŽ ããã¹ãŠã€ãã¬ãŒã·ã§ã³ãã ãšããããšã§ãã ã€ãŸãããã«ãžã§ãã¬ãŒã¿ãæå®ãããå Žå(以éãµããžã§ãã¬ãŒã¿ãšãã)ã ãµããžã§ãã¬ãŒã¿ã®ã€ãã¬ãŒã·ã§ã³ããã¹ãŠæžãã§ãã次ã®åŠçã«é²ãããšã«ãªããŸãã
ãã®ä»çµã¿ã«ãã£ãŠã³ã«ãŒãã³ã¯ãåŸ ã€(await)ããå®çŸããŠããŸãã(ããããã³ã°ã«ã€ããŠã¯åŸè¿°)
ã³ã«ãŒãã³ã¯ãã®æ§è³ªã«ããããã€ãã¬ãŒã·ã§ã³èªäœã®è¿åŽå€(yield
)ãã䜿ãããªãããã
ä»çµã¿ãšããŠã¯ãžã§ãã¬ãŒã¿ãšåãã§ãç®çã¯å€§ããç°ãªããšèšããŸãã
(ã³ã«ãŒãã³èªäœã®è¿åŽå€(return
)㯠Future
ã®çµæãšããŠéèŠãªã®ã§æ··åããªãããã«æ³šæ)
å®é Python3.4 ãŸã§ã¯ yield from
æã䜿ãããŠããŸããã Python3.5
ã§ç»å Žãã await
æã«åã£ãŠä»£ãããŸããã
- info
yield from
㯠foræã§åããŠããã®ãšã»ãŒåãæå³ããšèšããŸããã ããã¯å éšçãªè©±ã§å®ã¯è¥å¹²ã®éãããããŸããyield from
ã¯ã³ã«ãŒãã³ãåãåã£ãŠåŠçã§ããŸããã å®ã¯ã³ã«ãŒãã³ã¯ã€ãã©ãã«ã§ã¯ãªãã®ã§ foræã§åãããšãã§ããŸããã- error
- TypeError: 'coroutine' object is not iterable
yield from
ã«ãµããžã§ãã¬ãŒã¿ãæå®ãããå Žåã¯ããã®è¿åŽå€(return
)ã巊蟺ã«æ ŒçŽãããŸãã
await æã«æå®ã§ãããªããžã§ã¯ãã Awaitable ãšãããŸãã Awaitable ãªãªããžã§ã¯ãã¯ããã©ã«ã㧠Coroutine ãš FutureãTask(åŸè¿°)ã®ïŒã€ã§ãã
ããå°ã詳ãã話ããããšã¹ãã·ã£ã«ã¡ãœããã® __await__
ãå®çŸ©ãããŠãããã®ãšãªããŸããã
èªåã§ã¯ã©ã¹ãå®çŸ©ããããµãŒãããŒãã£ã©ã€ãã©ãªãå°å
¥ããªããã°æ°ã«ããå¿
èŠã¯ãªãã§ãã
ãªããæªå®äºãªFuture㯠loopã®ã³ãŒã«ããã¯ãå¥ã®ã³ã«ãŒãã³ã®äžã§(Futureã)æäœãã ã¹ããŒã¿ã¹ãçµäºããããšãæ³å®ããŠããŸãã
await ã®æåã«ã€ããŠ
awaitæãæªå®äºãªFutureãåãåããšããã®ã³ã«ãŒãã³ããããã¯ããå¥ã®å®è¡å¯èœãªã³ã«ãŒãã³ãå®è¡ããŸãã éäžã§Futureã®ã¹ããŒã¿ã¹ãå®äºã«ç§»è¡ãããšããããã¯ã解é€ããã³ã«ãŒãã³ãåéããŸãã
æåããå®äºããFutureãawaitæã«æå®ãããå Žåã¯æ®éã«ã¹ã«ãŒãããã ãã§ãã
åé 㧠IOåŸ
ã¡æéã«ã¶ã€ãããšå®è¡å¯èœãªå¥ã®åŠçãå²ãåœãŠã
ãšãããŸãããã ãIOåŸ
ã¡æéã«ã¶ã€ãããŸã§ããšããã®ãã
ãawaitæãæªå®äºãªFutureã«ééãããŸã§ããšããããšã«ãªããŸãã
awaitæãã³ã«ãŒãã³ãåãåããšã äžèšã®ããã«IOåŸ ã¡æéã«ã¶ã€ãããŸã§ã³ã«ãŒãã³ãåŒã³åºããªããåŠçãç¹ãã§ãããŸãã
flowchart TD direction LR subgraph coro1 a[åŠç1]-->b[result = await coro2]; j[return result]; end subgraph coro2 c[await future<br />DONE]-->d[result = await coro3]; b-->c; i[return result]-->j; end subgraph coro3 d-->e; e[result = await future<br />PENDING]-->f[return result]; f-->i; end subgraph others e-->g[ãããã¯ããŠããé<br />ä»ã®å®è¡å¯èœãªã³ã«ãŒãã³ã«<br />åŠçã移ã]; end
å°ãã€ãªãã£ãŠããŸãããã
- warning
- asyncio ã®é¢æ°ã§ã¯ã³ã«ãŒãã³ãåŒæ°ã«åãåããã®ããããŸããã ãã®å Žåã«æå®ããã®ã¯ãã³ã«ãŒãã³ãªããžã§ã¯ããã§ãã£ãŠããã³ã«ãŒãã³é¢æ°ãã§ã¯ãªãã®ã§æ³šæããŠãã ããã
- ã³ã«ãŒãã³é¢æ°ãå®è¡ããè¿åŽå€ãã³ã«ãŒãã³ãªããžã§ã¯ãã§ãã
async ãš awaitæã䜿ã£ãŠãïŒç§åŸ ã£ãåŸã«äœããã®æåãåºåããã³ã«ãŒãã³é¢æ°ã¯ä»¥äžã®ããã«æžããŸãã
async def sleep_and_print(txt): await asyncio.sleep(1) print(txt)
ãã®ç¶æ ã§ã¯ãŸã ã³ã«ãŒãã³ã¯å®è¡ã§ããªãã®ã§ã€ãã³ãã«ãŒãã®ç« ãŸã§èªã¿é²ããŠãã ããã
- info
async
/await
æ㯠Python3.5ããæ°ãã«ç»å ŽããäºçŽèªã§ããPython3.4ã®ãšãã¯æ¬¡ã®ããã«ããŠãžã§ãã¬ãŒã¿ãšããŠããŸãåŠçããŠããã®ã§ãã
- async
@asyncio.coroutine
ãã³ã¬ãŒã¿ã§ãžã§ãã¬ãŒã¿é¢æ°ãå²ãã(Python3.10ã§ãªããªãã®ã§äœ¿ããªãããš)@asyncio.coroutine def hello_world(): print("Hello World!")
- await
yield from
æã䜿ãã@asyncio.coroutine def sleep(): yield from asyncio.sleep(1)
- åŸæ¹äºææ§ç¶æã®ããããŸã
yield from
ã䜿ãããšãã§ããŸããã ã³ã«ãŒãã³ã®æ¬æ¥ã®çšéããèããã°ãawait
æã䜿ãã®ãé©åã§ãã - ãªããã³ã«ãŒãã³ã§
yield from
ã䜿ããã®ã¯asyncio.coroutine
ãã³ã¬ãŒã¿ã«ãã£ãŠå®çŸ©ããå Žåã®ã¿ã§ã async æã䜿ã£ãŠå®çŸ©ããã³ã«ãŒãã³ã®äžã§yield from
ã䜿ããš SyntaxError ã«ãªããŸãã SyntaxError: 'yield from' inside async function
- ã€ãŸãããããããã¯äœ¿ããªããªãã®ã§æ°ããã³ãŒãã§ã¯äœ¿ããªãããšã§ãã
- 該åœã³ãŒã
ã€ãã³ãã«ãŒã
JavaScript ã§ã¯ async
æã䜿ã£ãŠäœæããéåæé¢æ°ã¯ãã®ãŸãŸå®è¡ããããšãã§ããŸãããã
Pythonã®ã³ã«ãŒãã³ã¯ãã®ãŸãŸé¢æ°ãšããŠå®è¡ããŠãåŠçãããŸããã
ã³ã«ãŒãã³ãªããžã§ã¯ããçæãããŠçµããã§ãã
ããã¯ã³ã«ãŒãã³ã®å®æ ããžã§ãã¬ãŒã¿ã ãããšããã®ãçç±ã§ãã ãžã§ãã¬ãŒã¿ã¯ã€ãã¬ãŒã·ã§ã³ãé²ãããšãã«åã㊠æåã®yieldæãŸã§ å®è¡ãããŸãããã
ãå¯ãã®éãããã®ã³ã«ãŒãã³ãå®è¡ããŠããã(ã€ãã¬ãŒã·ã§ã³ãé²ããŠããã)ã®ãã€ãã³ãã«ãŒããšããããšã«ãªããŸãã IOã®åŸ ã¡æéã«ã¯ä»ã®åŠçãå²ãåœãŠããªã©ã®è£æ¹ããã£ãŠãããåãåã§ãã
- info
- è£æãšããã»ã©ã§ããããŸãããã
coro.send(None)
ãšããããšã§ãã³ã«ãŒãã³åäœã§ã€ãã¬ãŒã·ã§ã³ãé²ããããšãã§ããŸãã - 決ããŠæšå¥šããŠããããã§ã¯ãªãã®ã§èŠããå¿
èŠã¯ãããŸããã
ãããã°çšãªã
asyncio.run(coro)
ããã®ããããšæããŸãã - ãªãã
None
以å€ã send ãããšãšã©ãŒã«ãªããŸãã
- è£æãšããã»ã©ã§ããããŸãããã
- error
- TypeError: can't send non-None value to a just-started coroutine
ã€ãã³ãã«ãŒããªããžã§ã¯ãã®ååŸæ¹æ³
loop ã®ååŸæ¹æ³ã«ã¯ çŸç¶3ã€ã®æ¹æ³ããããŸã
- get_event_loop
get_event_loop ã§çæããã€ãã³ãã«ãŒãã¯èªåçã«ã¯ ã«ã¬ã³ãã€ãã³ãã«ãŒã (以éã«ã¬ã³ãã«ãŒããšãã) ãšããŠããŒã¯ãããäºåç®ä»¥é㯠ã«ã¬ã³ãã«ãŒããååŸãããŸãã
>>> import asyncio >>> loop = asyncio.get_event_loop() >>> loop2 = asyncio.get_event_loop() >>> loop2 is loop
ãã®èšäºã®ãµã³ãã«ã³ãŒãã§ã¯ loop ãªããžã§ã¯ãã®å®çŸ©ãçç¥ããŠããç®æããããŸããã äžèšã®æ¹æ³ã§äœæããŠãããšãèããã ããã
ãšããããã€ãã³ãã«ãŒãã®äœæã¯ããã ãç¥ã£ãŠãã°å€§äžå€«ã§ãã æŠèŠã ããç¥ããããšããæ¹ã¯ä»¥äžã¯èªã¿é£ã°ããŠããã§ãã
ã©ããã
asyncio.run
ãå®è¡ããŠããget_event_loop
ãåŒã¶ãšã©ã³ã¿ã€ã ãšã©ãŒãçºçããããšãããããã§ãã- error
- RuntimeError: There is no current event loop in thread 'MainThread'.
ãããèµ·ãããšãã®å¯ŸåŠæ³ãšããŠã¯ äœææžã¿ã® ã€ãã³ãã«ãŒããã«ã¬ã³ãã«ãŒããšããŠç»é²ããŠãããã°OKã§ãã
ã«ã¬ã³ãã«ãŒããšããŠç»é²ããã«ã¯
asyncio.set_event_loop(loop)
ã䜿ããŸãã
- get_running_loop
Python3.7ã§è¿œå ãããŸãããçŸåšåããŠããã€ãã³ãã«ãŒããããå Žåã¯ãããè¿åŽãã ãªããã°
RuntimeError
ãçºçããŸããããããã³ã«ãŒãã³ã®äžã§æå±ããŠããã€ãã³ãã«ãŒããåãããã®ãã®ã§ãããã ããã«ãããã±ããªã¬ãŒã§ loop ãªããžã§ã¯ããåŒãç¶ãå¿ èŠããªããªããŸãã
>>> async def check_loop(): ... await asyncio.sleep(1) ... return loop is asyncio.get_running_loop() ... >>> loop.run_until_complete(check_loop()) True >>> asyncio.get_running_loop() Traceback (most recent call last): File "<stdin>", line 1, in <module> RuntimeError: no running event loop
- new_event_loop
æ¢åã®ã«ã¬ã³ãã«ãŒããç¡èŠããŠãæ°èŠã®ã€ãã³ãã«ãŒããäœæããŸãã
get_event_loop
ã§äœã£ãã€ãã³ãã«ãŒããšã¯éã£ãŠèªåçã«ã«ã¬ã³ãã«ãŒããšã¯ãªããŸããã>>> import asyncio >>> loop = asyncio.get_event_loop() # new_event_loop ã¯å¿ ãæ°èŠã®ã€ãã³ãã«ãŒããçæããæ¢åã®ã€ãã³ãã«ãŒããšã¯éè€ããªã >>> loop2 = asyncio.new_event_loop() >>> loop is loop2 False >>> loop3 = asyncio.new_event_loop() >>> loop3 is loop2 False >>> loop3 is loop False # get_event_loop ã§ååŸããã€ãã³ãã«ãŒãã¯åãã get_event_loop ã§ååŸããã€ãã³ãã«ãŒããšã®ã¿äžèŽãã >>> loop4 = asyncio.get_event_loop() >>> loop4 is loop3 False >>> loop4 is loop2 False >>> loop4 is loop True # set_event_loop ãã€ãããš ç¹å®ã®ã€ãã³ãã«ãŒããã«ã¬ã³ãã«ãŒãã«èšå®ã§ãã >>> asyncio.set_event_loop(loop3) >>> loop5 = asyncio.get_event_loop() >>> loop5 is loop4 False >>> loop5 is loop3 True
set_event_loop
ãšããé¢æ°ã䜿ãããšã§ å¥ã®ã€ãã³ãã«ãŒããã«ã¬ã³ãã«ãŒããšããŠããŒã¯ã§ããŸãã
ã€ãã³ãã«ãŒãã®åããæ¹
ã€ãã³ãã«ãŒãã«ä»äºããããããã®æ¹æ³ã¯ããã€ããããŸãã
- asyncio.run
åŒæ°ã«æå®ãã ã³ã«ãŒãã³ãå®äºãããŸã§å®è¡ããŸãã Python3.7ã§è¿œå ãããŸããã
å éšçã«ã¯æ°èŠã® loop ãªããžã§ã¯ããäœã
loop.run_until_complete
(åŸè¿°)ãåŒã³åºãã ãã®ã·ã§ãŒãã«ããã®ãããªãã®ã§ãã泚æç¹ã¯ä»¥äžã®ïŒç¹ã§ã
æ°èŠã®ã€ãã³ãã«ãŒããçæããã
åŒæ°ã«ã¯ã³ã«ãŒãã³ããåããšããªã
>>> async def coro(seconds, value): ... await asyncio.sleep(seconds) ... return value + 100 ... >>> asyncio.run(coro(1, 100)) # ã³ã«ãŒãã³ã®å€ããã®ãŸãŸè¿åŽããã 200 >>> future = asyncio.gather(coro(1, 1), coro(2, 2)) # gather ã§ãŸãšããŠãã³ã«ãŒãã³ã§ãªããã°ã ã(gatherã¯Futureãè¿ã) >>> asyncio.run(future) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/Cellar/python/3.7.2_2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/runners.py", line 37, in run raise ValueError("a coroutine was expected, got {!r}".format(main)) ValueError: a coroutine was expected, got <_GatheringFuture pending>
- loop.run_forever
loop.run_foreverã¯æ°žä¹ ã«å®è¡ãç¶ããŸããå®è¡ããåŠçããªãå Žåã¯ãã£ãšãããã¯ããŸãããµãŒããŒçšéããªã
ã³ã«ãŒãã³ã§ã«ãŒããã¹ãããããªãéãæ¢ãŸããŸããã ãã®ã¡ãœããã¯åŒæ°ãåãåããªãã®ã§å®è¡å¯Ÿè±¡ã®åŠçã¯ã³ãŒã«ããã¯é¢æ°ã loop ã«èšå®ãããã
create_task
ã¡ãœãã (Taskã§åŸè¿°)㧠ç»é²ããŠãããå¿ èŠããããŸãã>>> async def coro(seconds, value): ... await asyncio.sleep(seconds) ... return value + 100 ... >>> loop = asyncio.get_event_loop() >>> loop.call_later(10, lambda l: l.stop(), loop) # 10ç§çµã£ãã loop ãã¹ããããã <TimerHandle when=10.638105535 <lambda>(<_UnixSelecto...e debug=False>) at <stdin>:1> >>> task1 = loop.create_task(coro(1, 1)) >>> task2 = loop.create_task(coro(3, 3)) >>> loop.run_forever() # ããã§10ç§ãããã¯ããã >>> task1 <Task finished coro=<coro() done, defined at <stdin>:1> result=101> >>> task2 <Task finished coro=<coro() done, defined at <stdin>:1> result=103>
- loop.run_until_complete
- loop.run_until_complete ã¯æå®ãã awaitable ãªãªããžã§ã¯ããçµäºãããŸã§å®è¡ããŸãã
>>> async def coro(seconds, value): ... await asyncio.sleep(seconds) ... return value + 100 ... >>> loop.run_until_complete(coro(1, 10)) 110 >>> loop.run_until_complete(asyncio.gather(coro(1, 10), coro(2, 20), coro(3, 30))) [110, 120, 130] >>> future = loop.create_future() >>> loop.run_until_complete(future) # future 㯠åæç¶æ ãpending ãªã®ã§ããã§æ¢ãŸããæ¬æ¥ã¯ callback ãã³ã«ãŒãã³ã®äžã§ã¹ããŒã¿ã¹ãå€ãã
- 以äžã¯ããããã®çµäºæ¡ä»¶ãšè¿åŽå€ã§ã
- ã³ã«ãŒãã³
- æåŸãŸã§å®è¡ãããšçµäºããã
- ã³ã«ãŒãã³é¢æ°ã®è¿åŽå€ããã®ãŸãŸè¿åŽå€ãšãªã
- Future
- ã¹ããŒã¿ã¹ãå®äºã«ãªããšçµäºãã(Taskãåã)
- çµæ(result)ãè¿åŽå€ãšãªã
call_*
ã¡ãœããã®ãã³ããªã³ã°
ããã®ã»ã¯ã·ã§ã³ã¯è¥å¹²å éšçãªè©±ã«ãªãã®ã§ãããããªããã°ã¹ã«ãŒã§OKã§ãã
loop 㯠call_later
, call_at
, call_soon
ãšåŒã°ããã¡ãœãããæã¡ã
ãã®åã®éããåïŒã€ã¯æéãæ¡ä»¶ãšããŠã³ãŒã«ããã¯é¢æ°ãé
延åŒã³åºããã
call_soon ã¯å³åº§ã«ã³ãŒã«ããã¯é¢æ°ãåŒã³åºããŸãã
- info
- call_at ã¯å®è¡äºå®æéããPythonã€ã³ã¿ããªã¿ãèµ·åããŠããã®æé(ç§)ãã§æå®ããŸãã
- ããã¯
time.monotonic()
ã䜿ã£ãŠæ±ããããŸãã - call_later ã¯çŸåšæéã«åŸ
ã¡ç§æ°ãå ã㊠call_at
ãåŒã³åºããŠããã ãã§ãã ãœãŒã¹ã³ãŒãã確èªããŸããã
call_later
以å€ã«call_at
ãåŒã³åºããŠããæ©èœã¯ãªãããã§ãã (èµ·åæéã¯ã€ã³ã¿ãŒãã§ãŒã¹ãšããŠäœ¿ãã¥ãããã..)
äžããããã³ãŒã«ããã¯é¢æ°ã¯ Handle
ãŸã㯠TimerHandle
ãšåŒã°ããã©ãããŒã¯ã©ã¹ã§å
ãŸããæ¡ä»¶ãæºããããšãã«çºç«ããŸãã
- call_later, call_at 㯠TimerHandle
- call_soon 㯠Handle
TimerHandle 㯠å®è¡äºå®æéãå
ã«å€§å°æ¯èŒãã§ããããã«ãªã£ãŠããŸãã
heapq.heapfy
ãšããé¢æ°ã䜿ã£ãŠæå°ã® TimerHandle
ããçŽè¿ã«å®è¡äºå®ã®ã³ãŒã«ããã¯ããšããŠååŸãå®è¡ããŠããŸãã
ã³ã«ãŒãã³å
ã§åŒã³åºããã await asyncio.sleep(seconds)
ãã©ã®ãããªåŠçããã©ããèŠãŠã¿ãŸãããã
- future ãäœã
- æå±ããloop ãªããžã§ã¯ãã®
call_later
ãåŒã³åºãcall_later
ãåŒã³åºããcall_at
ã«ãã TimerHandle ãªããžã§ã¯ããäœãããå®è¡äºå®ã® TimerHandle ãšã㊠loopãªããžã§ã¯ãã®å éšã«ä¿åãã (loop._scheduled
)- å®è¡äºå®ã® TimerHandle ã®ãã¡çŽè¿(æå°)ã®ãã®ãååŸããå®è¡äºå®æå»ãšçŸåšæå»ã®å·®åãã¿ã€ã ã¢ãŠãç§æ°ãšããŠ
selectors.select ã®åŒæ°ã«æå®ããŠåŒã³åºããŠåŠçããããã¯ãã
- ãã®æç¹ã§å®è¡å¯èœãª TimerHandle ãããå Žåã¯åŸ ããããã«ãã¡ããå®è¡ããã
- å®è¡äºå®ã® TimerHandle ã®ãã¡ãå®è¡äºå®æå»ãçŸåšæå»ãããåã®ãã®ã
å®è¡å¯èœãª TimerHandle ãšã㊠loopãªããžã§ã¯ãã®å
éšã«ä¿åãã (
loop._ready
)- ãã®ãšã å®è¡äºå®ãªã¹ã (
loop._scheduled
) ããã¯åé€ããã
- ãã®ãšã å®è¡äºå®ãªã¹ã (
- å®è¡å¯èœãª TimerHandle ãé ã«æœåºããçŽä»ããããã³ãŒã«ããã¯é¢æ°ãå®è¡
- ã³ãŒã«ããã¯é¢æ°ã«ãã future ã®ã¹ããŒã¿ã¹ãçµäºãšãªã
- future ã await ãã
- 該åœã³ãŒã
IOå€éå
ãã³ããããã³ã°ã¢ãŒãã®ãã¡ã€ã«ãã£ã¹ã¯ãªãã¿(以éFDãšãã)ãè€æ°çšæããŠç£èŠããããšãIOå€éåãšèšããŸãã
Pythonã®åŠçã¯åºæ¬çã«ããããã³ã°ã§ãã ãããã¯ãŒã¯IOã®æéãä»ã®åŠçã«å²ãåœãŠãããšèšã£ãŠããããããã³ã°IO(ãœã±ãã)ãçšããŠããåŠçã§ã¯éä¿¡æéã¯ç¡é§ã«åŸ ããããŠããŸããŸãã
ããã«å¯Ÿãããã³ããããã³ã°IO ãšãããã®ã䜿ããšãœã±ãããå§ããšããFDã®èªã¿æžã㯠ãã®å¯åŠã«ãããããããã«åŠçã次ã«ç§»ããŸãã
ãšã¯ãããããã§ã¯FDã䜿çšå¯èœãã©ããããããªãã®ã§ç£èŠãå¿ èŠã«ãªããŸãã
- info
- ç£èŠãšããåŠçãæçŽã«èãããšwhileæã§ããããåããŠãœã±ããã®ç¶æ ã«ããåå²ãããããªå®è£ ãæãæµ®ãã¶ãããããŸããã
- ãããããã§ã¯ã«ãŒãã空åãããããšã§CPU䜿çšçãããªãé«ããªã£ãŠããŸããŸãã
ããã¯
ããžãŒã«ãŒã
ãšåŒã°ããææ³ã§ ãã³ããããã³ã°ãœã±ãã - ãœã±ããããã°ã©ãã³ã° HOWTO Python 3.7.3 ããã¥ã¡ã³ã ã§ã¯æããªæ¹æ³ãšããŠçŽ¹ä»ãããŠããŸãã
Python以å€ã®èšèªã§ãã£ãŠããããã¯ãŒã¯ããã°ã©ãã³ã°ãããããšãããã° FDã®ç£èŠãšèãã°ããããŒã selectã§ããããšãªãã§ããããæŠãæ£è§£ã§ãã
Python3.4以éã§ã¯ã selectors
ãšåŒã°ãããã«ãã€ã³ã¢ãžã¥ãŒã«ããããŸãã
ãã㯠select ã®ã©ãããŒã®ãããªãã®ã§ãOSããæäŸãããŠããç£èŠæ©èœã®ãã¡æãå¹ççãªãã®ãèªåçã«éžæããããšãã£ãããããã®ã§ãã
ã€ãã³ãã«ãŒã ã¯ããã® selectors ãçšããŠãFDã®ç£èŠãè¡ããŸãã ç£èŠèªäœã¯ããããã³ã°åŠçãªã®ã§ãèªã¿æžãå¯èœãªFDããªããã°åŠçã¯ãããã¯ãããŸãã ããžãŒã«ãŒããšéãCPUã®æ¶è²»ãæããããŸãã
ãããã¯ãŒã¯éä¿¡ãè¡ãéåæåŠçã§ã¯ãããã€ãã®ãœã±ããã selectors ã¡ãœããã«ãã£ãŠç£èŠãããŸãã
- info
- ãããã¯ãŒã¯éä¿¡ãè¡ããšãã ãã§ãªãã€ãã³ãã«ãŒãèªèº«ãäžçµã®ãœã±ãããæã£ãŠããã
ãœã±ããã®ãããã¯ã«ãã
asyncio.sleep
æ©èœãè¡šçŸããŠããŸãã - ã€ãã³ãã«ãŒãã¯call_laterã§ç»é²ãããå®è¡äºå®ãªãã³ãã«ã®ãã¡å®è¡äºå®æå»ãæãå€ã(å°ãã)ãã®ãåãåºã
ãçŸåšæå»ãšã®å·®åãããåŸ
ã¡æéããšããŠãç£èŠåŠç(
selectors.select
)ã®ã¿ã€ã ã¢ãŠãã«æå®ããããããã®æéåã ããããã¯ãããŸãã ãããasyncio.sleep
ã®æ£äœã§ãã - ãã ãããã§ã«å®è¡å¯èœãªãã³ãã«ãããå Žåã¯åŸ ã¡æéã0ãšããŸãã
- (æå㯠asyncio.sleep ã§äœããã Future ïŒã€ã«ã€ãïŒã€ã®ãœã±ããããã£ãŠ selectors ã§ç£èŠããŠãã®ããšæã£ãŠãŸãããéããŸãã..)
- ãããã¯ãŒã¯éä¿¡ãè¡ããšãã ãã§ãªãã€ãã³ãã«ãŒãèªèº«ãäžçµã®ãœã±ãããæã£ãŠããã
ãœã±ããã®ãããã¯ã«ãã
- 該åœã³ãŒã
- base_events.BaseEventLoop
- proactor_events.BaseProactorEventLoop
- selector_events.BaseSelectorEventLoop
- unix_events._UnixSelectorEventLoop
selector_events.BaseSelectorEventLoop
ãç¶æ¿- unix_events.SelectorEventLoop ãšåã
- windows_events._WindowsSelectorEventLoop
selector_events.BaseSelectorEventLoop
ãç¶æ¿- windows_events.SelectorEventLoop ãšåã
- windows_events.ProactorEventLoop
proactor_events.BaseProactorEventLoop
ãç¶æ¿
Task
Taskã¯äžã€ã®ã³ã«ãŒãã³ã«çŽã¥ãçµæãªããžã§ã¯ãã§ãã Futureãç¶æ¿ããŠå®çŸ©ãããŠããã®ã§åœ¹å²ã¯ããªã䌌ãŠããŸãã(åœç¶ Awaitableã§ã)
Future ã çµæãçµäºã¹ããŒã¿ã¹ãèªåã§æ ŒçŽããå¿ èŠããã£ãã®ã«å¯Ÿãã Task ã¯ã³ã«ãŒãã³ã«çŽä»ããã³ã«ãŒãã³ã®çµæãšçµäºã¹ããŒã¿ã¹ãèªåçã«æ ŒçŽãããŸãã éã«æåã§çµæãå ¥ããããšãåºæ¥ãŸããã
ããã§ãã¡ãã¡ã³ãŒã«ããã¯é¢æ°ãæžãå¿ èŠããªããªããŸããã
Task 㯠loop.create_task(ã³ã«ãŒãã³)
ã®ããã«äœããŸãã
ãã®ã¡ãœããã¯Taskãªããžã§ã¯ããè¿åŽããã®ã§ãå¿
èŠã«å¿ããŠå¥ã®ã³ã«ãŒãã³ã«æž¡ããªã©ããŸãã
>>> async def coro(seconds, value): ... await asyncio.sleep(seconds) ... return value + 100 >>> task1 = loop.create_task(coro(1, 1)) >>> task2 = loop.create_task(coro(2, 100)) >>> task3 = loop.create_task(coro(3, 301)) >>> loop.run_until_complete(asyncio.gather(task1, task2)) # ãããŠtask3ã¯åŸ ããªã [101, 200] >>> task1 <Task finished coro=<coro() done, defined at <stdin>:1> result=101> >>> task2 <Task finished coro=<coro() done, defined at <stdin>:1> result=200> >>> task3 <Task pending coro=<coro() running at <stdin>:2> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x10eca9eb8>()]>>
次ã¯é©åœãªäŸå€ãèµ·ãããŠã¿ãŸãã
>>> async def coro(seconds, value): ... await asyncio.sleep(seconds) ... if not value: ... raise ValueError(value) ... return value + 100 ... >>> task1 = loop.create_task(coro(1, 1)) >>> task2 = loop.create_task(coro(2, 0)) >>> loop.run_until_complete(asyncio.gather(task1, task2)) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete return future.result() File "<stdin>", line 4, in coro ValueError: 0 >>> task1 <Task finished coro=<coro() done, defined at <stdin>:1> result=101> >>> task2 # äŸå€ãçºçããå Žåã status ã¯äžå¿çµäºãšãªã <Task finished coro=<coro() done, defined at <stdin>:1> exception=ValueError(0)>
çµäºã¹ããŒã¿ã¹ãèªåçã«æ ŒçŽããããšã¯èšããŸãããã ã¹ããŒã¿ã¹ããã£ã³ã»ã«ã«ãããå Žåã¯èªåã§æ ŒçŽããå¿ èŠããããŸãã
ä»åã¯äžå®ç§æ°çµéåŸã«ãã£ã³ã»ã«ããã ãã®ã³ã«ãŒãã³ cancel ãäœã£ãŠã¿ãŸããã
>>> async def cancel(seconds, task=None): ... await asyncio.sleep(seconds) ... if task: ... task.cancel() ... >>> task2 = loop.create_task(cancel(2)) # task2 㯠2ç§åŸã«çµããããã«ãã >>> task1 = loop.create_task(cancel(1, task2)) # task1 㯠1ç§åŸã«çµãã£ãŠ task2ããã£ã³ã»ã«ãã >>> loop.run_until_complete(asyncio.gather(task1, task2)) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete return future.result() concurrent.futures._base.CancelledError >>> task1 <Task finished coro=<cancel() done, defined at <stdin>:1> result=None> >>> task2 <Task cancelled coro=<cancel() done, defined at <stdin>:1>>
ã¿ã¹ã¯ã§ã¯ cancel ãããš CancelledError
äŸå€ãéåºãããããã§ãã
- info
loop.create_task(coro)
ãšasyncio.ensure_future(coro_or_future, *, loop=None)
ã®éã- Python3.7 ã§
loop.create_task
ãåºçŸãããŸã§ã ã¿ã¹ã¯ã®çæã«ã¯asyncio.ensure_future
ã䜿ãããŠããŸããã ensure_future
ãªã®ã« future ãããªã㊠taskãªã®ïŒãšæããŸããã å®éã«äœãããã®ã¯ã¿ã¹ã¯ãªãã§ããçœ ã§ããã- Python3.7以éã§ã¯
loop.create_task
ã䜿ãããšãæšå¥šãããŠããŸãã - å®éã«éãããããšãããšã
create_task
ã§ã¯ã³ã«ãŒãã³ããåãåããªããšããç¹ã§ãã - åœç¶
asyncio.gather
ã§ã³ã«ãŒãã³ã®çµæããŸãšãã Future ãåãåããŸããã - ã¿ã¹ã¯ã¯äžã€ã®ã³ã«ãŒãã³ã«çŽã¥ããã®ãªã®ã§ãããã¯åŠ¥åœãªã€ã³ã¿ãŒãã§ãŒã¹ã ãšå人çã«ã¯æããŸãã
- (3.7以éã§ã¯)
ensure_future
ã¯åãåã£ãåŒæ°ãã³ã«ãŒãã³ã®å Žå㯠å éšçã«create_task
ã«æž¡ãã ãã§ãã - create_task ãåŒã°ãããš
loop.call_soon
ã䜿ã£ãŠã³ã«ãŒãã³ãå®è¡å¯èœãªã¹ã±ãžã¥ãŒã«ãšããŠã«ãŒãã«ç»é²ããŸãã - ãªãã ã³ã«ãŒãã³å
ã®
await
æã§å¥ã®ã³ã«ãŒãã³ãåŒã³åºãå Žåã¯ãcall_soon
ãä»ããçŽæ¥åŒã³åºãããŸããawait
æãyield from
æã ãšæãã°åœç¶ã®æåããç¥ããŸãããã - asyncio.create_task
- asyncio.ensure_future vs. BaseEventLoop.create_task vs. simple coroutine?
- Proposal: Rename ensure_future to create_task · Issue #477 · python/asyncio
æåŸã«é ã®äžã®åŒã³åºãã€ã¡ãŒãžå³çãªãã®(å šéšã¯ç¡çãªã®ã§éèŠã£ãœããšããã ã)
graph TD asyncio.sleep --> loop.call_later asyncio.ensure_future --> |ã³ã«ãŒãã³ãªã| loop.create_task subgraph Event loop loop.create_task --> |coro.send| loop.call_soon loop.call_later --> loop.call_at loop.call_at --> |TimerHandle| loop._scheduled loop.call_soon --> |Handle| loop._ready loop._scheduled --> |TimerHandle.when <= çŸåšæé| loop._ready end loop._ready -->|Handle,TimerHandle| handle.run
- info
- è€æ°ã® Coroutine (Future) ã®çµäºãåŸ
ã€ããã®é¢æ°ãšããŠ
asyncio.gather
ãšasyncio.wait
ããããŸãã asyncio.gather
㯠awaitable ãªãªããžã§ã¯ããå¯å€é·ä»®åŒæ°ãšããŠè€æ°æå®ãããšã ãããããŸãšãäžãã Future ãªããžã§ã¯ããè¿åŽããŸãã- äžã®ãªããžã§ã¯ããå®äºãããš Future ã¯å¯å€é·ä»®åŒæ°ã«æå®ããã®ãšåãé çªã§ Future ãªããžã§ã¯ãã«çµæãæ ŒçŽãããŸãã
>>> future = asyncio.gather(asyncio.sleep(3, 1), asyncio.sleep(2, 2), asyncio.sleep(1, 3)) >>> loop.run_until_complete(future) [1, 2, 3] >>> future <_GatheringFuture finished result=[1, 2, 3]>
- https://docs.python.org/ja/3/library/asyncio-task.html
asyncio.wait
ãåæ§ã« awaitable ãªãªããžã§ã¯ããè€æ°åãåããŸããã å¯å€é·åŒæ°ã§ã¯ãªã list ã set ãªã©ã®ã·ãŒã±ã³ã¹ãæå®ããŸãã- è¿åŽå€ã¯
gather
ãšã¯éã Coroutine ãè¿åŽããŸãã ã³ã«ãŒãã³èªäœã®è¿åŽå€ã¯(done, pending)
ã®ãã㪠set ã® tuple ã§ãã - ãŸããã¿ã€ã ã¢ãŠãæéãã³ã«ãŒãã³ã®çµäºæ¡ä»¶ã¯åŒæ°ãšããŠæå®ã§ããŸãã
>>> coro = asyncio.wait([asyncio.sleep(3, 1), asyncio.sleep(2, 2), asyncio.sleep(1, 3)], timeout=2.1) >>> done, pending = loop.run_until_complete(coro) >>> done {<Task finished coro=<sleep() done, defined at /usr/lib64/python3.7/asyncio/tasks.py:555> result=3>, <Task finished coro=<sleep() done, defined at /usr/lib64/python3.7/asyncio/tasks.py:555> result=2>} >>> pending {<Task pending coro=<sleep() running at /usr/lib64/python3.7/asyncio/tasks.py:568> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x10d23a198>()]>>}
- ä»åã®äŸã§ã¯çµäºæ¡ä»¶ãæå®ããŠããŸãããã
return_when
åŒæ°ã«ã¯ä»¥äžã®æååãæå®ããããšãã§ããŸãã - FIRST_COMPLETED
- ããããã®ãã¥ãŒãã£ãçµäºããããã£ã³ã»ã«ããããšãã«è¿ããŸãã
- FIRST_EXCEPTION
- ããããã®ãã¥ãŒãã£ãäŸå€ã®éåºã§çµäºããå Žåã«è¿ããŸããäŸå€ãéåºãããã¥ãŒãã£ããªãå Žåã¯ãALL_COMPLETED ãšç䟡ã«ãªããŸãã
- ALL_COMPLETED
- ãã¹ãŠã®ãã¥ãŒãã£ãçµäºããããã£ã³ã»ã«ããããšãã«è¿ããŸãã
- https://docs.python.org/ja/3/library/asyncio-task.html
- è€æ°ã® Coroutine (Future) ã®çµäºãåŸ
ã€ããã®é¢æ°ãšããŠ
å¿çš
ããããã³ã°é¢æ°ã䜿ããã
ãããŸã§ã®åŠçã¯ãã¹ãŠãã³ããããã³ã°ãªé¢æ°ã䜿ã£ãŠããŸãããã Pythonã®é¢æ°ã¯åºæ¬çã«ããããã³ã°ã§ããããµãŒãããŒãã£ã©ã€ãã©ãªã§ã¯ asyncio ã«å¯Ÿå¿ããŠãªããã®ãå€ãã§ãããã
ãšã¯ãããé¢æ°ã®ã³ãŒããæžãå€ããŠã³ã«ãŒãã³ã«å€ãããªã©ã§ããã¯ãããããŸããã
ãã㧠loop.run_in_executor
ã¡ãœããã䜿ããŸãã
ãã㯠multi threading / processing ã«ãã£ãŠéåæå®è¡ãå®çŸããŠããŸãã
run_
ããå§ãŸã£ãŠããã®ã§ loop.run_until_complete
ãªã©ãšæ··åããŠããŸãããã§ããã ãã㯠Future ãäœãããã®ã¡ãœãããªã®ã§å¥ç©ã§ãã
以äžã®ïŒäŸã¯ãããã ïŒç§åŸã«åãçµæãåºåããŸãã
>>> import time >>> import concurrent.futures >>> def not_coro(seconds, value): ... time.sleep(seconds) ... return value + 100 ... # pool ãæå®ããªã >>> loop.run_until_complete(asyncio.gather( ... loop.run_in_executor(None, not_coro, 1, 1), ... loop.run_in_executor(None, not_coro, 2, 20), ... loop.run_in_executor(None, not_coro, 3, 300), ... )) [101, 120, 400] # ã¹ã¬ããããŒã« >>> with concurrent.futures.ThreadPoolExecutor() as pool: ... loop.run_until_complete(asyncio.gather( ... loop.run_in_executor(pool, not_coro, 1, 1), ... loop.run_in_executor(pool, not_coro, 2, 20), ... loop.run_in_executor(pool, not_coro, 3, 300), ... )) ... [101, 120, 400] # ããã»ã¹ããŒã« >>> with concurrent.futures.ProcessPoolExecutor() as pool: ... loop.run_until_complete(asyncio.gather( ... loop.run_in_executor(pool, not_coro, 1, 1), ... loop.run_in_executor(pool, not_coro, 2, 20), ... loop.run_in_executor(pool, not_coro, 3, 300), ... )) ... [101, 120, 400]
è¿åŽããããªããžã§ã¯ã㯠future ãªããžã§ã¯ããªã®ã§ä»ã® ãã³ããããã³ã°é¢æ°ãšåãããã« await ããããšãã§ããŸãã
第äžåŒæ°ã«ã¯ ã¹ã¬ããããŒã«ãæå®ããŸããã None
ãæå®ããããšã§çç¥ã§ããŸãã
çç¥ããå Žåã¯ãã®ãã³ã«å¿
èŠãªæ°ã®ã¹ã¬ãããäœãããããã§ãã
æåŸã®äŸã®ããã«ãããã»ã¹ããŒã«ãæå®ããããšãã§ããŸãã ããã«ãããCPUããŠã³ãã®åŠçãå¹çããåŠçããããšãã§ããŸãã (ãã¡ããã³ã¢æ°ãïŒã€ä»¥äžã®å Žåã«éããŸãã)
ã€ãã³ãã«ãŒãã®ããªã·ãŒ
ã€ãã³ãã«ãŒãã«ã¯ããªã·ãŒãšãããã®ãèšå®ã§ããŸãã
ããã©ã«ãã§ã¯ä»¥äžã®ããããã䜿ãããéžæã§ããŸãã
- DefaultEventLoopPolicy
- WindowsProactorEventLoopPolicy
- çŸç¶ã¯ Windows ã§ãã䜿ããªã
- https://github.com/python/cpython/blob/3.7/Lib/asyncio/windows_events.py
詳ãã調ã¹ãŠãªããã© IOå€éåã§ç£èŠããã IOå®äºããŒããç£èŠãããã£ãŠããšã®ããã§ããã çŸç¶åŸè 㯠Windowsãã§ããå©çšã§ããŸããã
ãããã®ã¯ã©ã¹ãç¶æ¿ããŠã¡ãœããããªãŒããŒã©ã€ãããŠã asyncio.set_event_loop_policy
é¢æ°ã§ããªã·ãŒç»é²ããã° loopãªããžã§ã¯ãã®ååŸæ¡ä»¶ãå€ãããã§ããŸãã
class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy): def get_event_loop(self): """Get the event loop. This may be None or an instance of EventLoop. """ loop = super().get_event_loop() # Do something with loop ... return loop asyncio.set_event_loop_policy(MyEventLoopPolicy())
https://docs.python.org/3/library/asyncio-policy.html
ä»æŽã§ããã ãã®èšäºã§ã¯ DefaultEventLoopPolicy
ã䜿ãåæã§æžããŠãŸãã
ãããã°ã¢ãŒã
asyncio ã®ã³ãŒãå ã§ã¯ é©åã«ãã°ãåããŠããã®ã§ã ãããã°ã¢ãŒãã«ããŠãã®ã³ã°èšå®ã調æŽããŠãããã°ãã³ã³ãœãŒã«ã«ãããã°æ å ±ã衚瀺ãããåé¡è§£æ±ºã«åœ¹ç«ã¡ãŸãã
ç°å¢å€æ°
PYTHONASYNCIODEBUG=1
ãèšå®ããäžã§ Python ã€ã³ã¿ããªã¿ãèµ·å(å®è¡)ãããã°ã¬ãã«ã
DEBUG
ã«èšå®ããlogging.basicConfig(level=logging.DEBUG)
asyncio.run
ã䜿ãå Žådebug
åŒæ°ã«True
ãæå®ãã>>> asyncio.run(coro_func(), debug=True) DEBUG:asyncio:Using selector: KqueueSelector INFO:asyncio:poll 999.905 ms took 1004.213 ms: timeout DEBUG:asyncio:Close <_UnixSelectorEventLoop running=False closed=False debug=True>
loop
ãªããžã§ã¯ãã䜿ãå Žåãloop.set_debug(True)
ãå®è¡ãã>>> loop = asyncio.get_event_loop() DEBUG:asyncio:Using selector: KqueueSelector >>> loop.set_debug(True) >>> loop.run_until_complete(coro_func()) INFO:asyncio:poll 999.749 ms took 1001.260 ms: timeout
ãããã¯ãŒã¯éä¿¡
asyncio ã¯ãããã¯ãŒã¯éä¿¡ãæ±ãããã®æ©èœãããã€ããã¡ãŸãã
ããŸã詳ããã¯ãããŸããããå°ãã ããµã³ãã«ãèŠãŠãããŸãããã(ããæ°åããªãã®ã§é)
Transports and Protocols
loop.create_connection()
ã®ãããª
ã€ãã³ãã«ãŒãã®äœã¬ãã«APIããå©çšããããããã¯ãŒã¯éä¿¡ãå®è£
ããããã¯ã©ã¹é¡ã§ãã
ããã㯠ã©ã€ãã©ãªããã¬ãŒã ã¯ãŒã¯ããåŒã°ãããããªãã®ã§ããã ã¢ããªã±ãŒã·ã§ã³ããåŒã°ããããšã¯æåŸ ãããŠããŸããã
ããã§ã¯ããã¥ã¡ã³ãã«åŸã£ãŠã UDPã® ãšã³ãŒãµãŒããŒã®ãµã³ãã«ãè©ŠããŠã¿ãŸãããã
- Server
- Client
>>> import asyncio >>> >>> >>> class EchoServerProtocol: ... def connection_made(self, transport): ... self.transport = transport ... ... def datagram_received(self, data, addr): ... message = data.decode() ... print('Received %r from %s' % (message, addr)) ... print('Send %r to %s' % (message, addr)) ... self.transport.sendto(data, addr) ... >>> >>> async def main(): ... print("Starting UDP server") ... ... # Get a reference to the event loop as we plan to use ... # low-level APIs. ... loop = asyncio.get_running_loop() ... ... # One protocol instance will be created to serve all ... # client requests. ... transport, protocol = await loop.create_datagram_endpoint( ... lambda: EchoServerProtocol(), ... local_addr=('127.0.0.1', 9999)) ... ... try: ... await asyncio.sleep(3600) # Serve for 1 hour. ... finally: ... transport.close() ...
>>> import asyncio >>> >>> >>> class EchoClientProtocol: ... def __init__(self, message, loop): ... self.message = message ... self.loop = loop ... self.transport = None ... self.on_con_lost = loop.create_future() ... ... def connection_made(self, transport): ... self.transport = transport ... print('Send:', self.message) ... self.transport.sendto(self.message.encode()) ... ... def datagram_received(self, data, addr): ... print("Received:", data.decode()) ... print("Close the socket") ... self.transport.close() ... ... def error_received(self, exc): ... print('Error received:', exc) ... ... def connection_lost(self, exc): ... print("Connection closed") ... self.on_con_lost.set_result(True) ... >>> >>> async def main(): ... # Get a reference to the event loop as we plan to use ... # low-level APIs. ... loop = asyncio.get_running_loop() ... ... message = "Hello World!" ... transport, protocol = await loop.create_datagram_endpoint( ... lambda: EchoClientProtocol(message, loop), ... remote_addr=('127.0.0.1', 9999)) ... ... try: ... await protocol.on_con_lost ... finally: ... transport.close() ...
>>> asyncio.run(main()) Starting UDP server Received 'Hello World!' from ('127.0.0.1', 58632) Send 'Hello World!' to ('127.0.0.1', 58632)
>>> asyncio.run(main()) Send: Hello World! Received: Hello World! Close the socket Connection closed
Stream
äžè¿°ãã Transport ãš Protocol ã䜿ã£ãäžäœå®è£ ããã¡ãã® Stream ã§ãã
ããã§ãããã¥ã¡ã³ãã«åŸã åçŽãª TCPã® EchoServer ãš EchoClient ãäœã£ãŠã¿ãããšã«ããŸãããã
(å°ãããããŸãã)
- Server
- Client
>>> import asyncio >>> import time >>> async def handle_echo(reader, writer): ... data = await reader.read(100) ... message = data.decode() ... addr = writer.get_extra_info('peername') ... await asyncio.sleep(5) # 5ç§åŸ 〠... writer.write(data) ... print(f"Sent {message!r} back to {addr!r}") ... await writer.drain() ... writer.close() ... >>> async def main(): ... server = await asyncio.start_server(handle_echo, '127.0.0.1', 7777) ... addr = server.sockets[0].getsockname() ... async with server: ... await server.serve_forever()
>>> import asyncio >>> async def send(message): ... reader, writer = await asyncio.open_connection('127.0.0.1', 7777) ... writer.write(message.encode()) ... print(f'Sending {message}') ... data = await reader.read(100) ... print(f'Received: {data.decode()!r}') ... writer.close() ... await writer.wait_closed() ...
>>> asyncio.run(main()) # . # . # . # . # . # . # . # . # 5ç§åŸ Sent 'h' back to ('127.0.0.1', 58298) Sent 'e' back to ('127.0.0.1', 58299) Sent 'l' back to ('127.0.0.1', 58300) Sent 'l' back to ('127.0.0.1', 58301) Sent 'o' back to ('127.0.0.1', 58302)
>>> loop = asyncio.get_event_loop() >>> loop.run_until_complete(asyncio.gather( ... send('h'), send('e'), send('l'), send('l'), send('o'))) Sending h Sending e Sending l Sending l Sending o # 5ç§åŸ Received: 'h' Received: 'e' Received: 'l' Received: 'l' Received: 'o'
éèŠãªã®ã¯ ãµãŒããŒåŽã® ãã³ãã«çšã³ã«ãŒãã³é¢æ°ã§ã¯
reader
, writer
åŒæ°ãåãåããã¯ã©ã€ã¢ã³ãåŽã§ã¯ã³ã«ãŒãã³å
ã§èªåã§çæããŸãã
ãµãŒããã¯ã©ã€ã¢ã³ãã¯ããããªããžã§ã¯ããéããŠã ãäºãã®ã¿ã€ãã³ã°ã§ãœã±ããã®èªã¿æžããããŠãããŸãã
çµããã«
ããŒãžã§ã³ãéããã«é£ãæ©èœãã ãã ããšå å®ããŠããŠãPythonã§éåæåŠçãæžãåå£ãæŽã£ãŠããŸãããã
以å㯠Twisted ãªã©ã®ãµãŒãããŒãã£ã©ã€ãã©ãªãçšããã®ãéäŸã§ãããã ãããã㯠asyncio ãããŒã¹ãšããã©ã€ãã©ãªãããããçãŸããŠããã§ãããã
åé ã§ãèšããŸããããããããã®èšäºã«ãäžè©±ã«ãªããŸããã èšäºãã¬ãã¥ãŒããŠãããå¿åã®æ¹ãš @shimizukawa ã«ãæè¬ã
ããããšãããããŸããã
åè
- Pythonã®éåæéä¿¡ïŒasyncioã¢ãžã¥ãŒã«ïŒå ¥éãæžããŸãã - ããããã¯æãžãš
- Pythonã§åæé¢æ°ãšéåæé¢æ°ãçµ±äžçã«æ±ã | Hatch tech blog
- pythonã®asyncioã§run_in_executor()ã䜿ã£ãŠããããã¯ããŠãããã«èŠããŠäžæãåŠçãéãããªããšæãããšãã - podhmo's diary
- 次äžä»£æšæºéåæI/Oãã¬ãŒã ã¯ãŒã¯ asyncio (Tulip) - methaneã®ããã°
- Pythonã«ãããéåæåŠç: asyncioéåŒããªãã¡ã¬ã³ã¹ - Qiita
- Pythonã®éåæI/OïŒasyncioïŒãè©Šã
- Pythonã§éåæåŠçïŒasyncioïŒ- ã€ãã³ããªããžã§ã¯ã | TomoSoft
- Pythonã®asyncioã§éåæã«ãªã¯ãšã¹ããé£ã°ã - sambaiz-net
- Goãä»ã®å€ãã®èšèªã§ã®éåæããã°ã©ãã³ã°ãããåªããŠããçç±
- Python asyncio: Future, Task and the Event Loop | Abu Ashraf Masnun
- Detailing Python\'s Coroutine out of History - Speaker Deck