2019-06-22

[Python] šŸ° ćŖ悓ćØćŖ恏ē†č§£ć™ć‚‹asyncio šŸ¢

å¤§å¤‰ćŠć¾ćŸć›ć—ć¾ć—ćŸć€‚ ę•°å¹“å‰ć‹ć‚‰ćšć£ćØę›ø恏ę›ø恏ćØ詐ę¬ŗć—ć¦ććŸ 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ć‚Æćƒ©ć‚¹ć‚’ē›“恫触悋恮ćÆć‚„ć‚ć¾ć—ć‚‡ć†ć€‚
č©²å½“ć‚³ćƒ¼ćƒ‰

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

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 恧ē›£č¦–恗恦悋恮恋ćØę€ć£ć¦ć¾ć—ćŸćŒé•ć„ć¾ć—ćŸ..)
č©²å½“ć‚³ćƒ¼ćƒ‰

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

åæœē”Ø

ćƒ–ćƒ­ćƒƒć‚­ćƒ³ć‚°é–¢ę•°ć‚’ä½æ恄恟恄

ć“ć“ć¾ć§ć®å‡¦ē†ćÆć™ć¹ć¦ćƒŽćƒ³ćƒ–ćƒ­ćƒƒć‚­ćƒ³ć‚°ćŖé–¢ę•°ć‚’ä½æć£ć¦ćć¾ć—ćŸćŒć€ 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ćƒć‚¦ćƒ³ćƒ‰ć®å‡¦ē†ć‚’効ēŽ‡ć‚ˆćå‡¦ē†ć™ć‚‹ć“ćØćŒć§ćć¾ć™ć€‚ (ć‚‚ć”ć‚ć‚“ć‚³ć‚¢ę•°ćŒļ¼’恤仄äøŠć®å “åˆć«é™ć‚Šć¾ć™ćŒ)

ć‚¤ćƒ™ćƒ³ćƒˆćƒ«ćƒ¼ćƒ—ć®ćƒćƒŖć‚·ćƒ¼

ć‚¤ćƒ™ćƒ³ćƒˆćƒ«ćƒ¼ćƒ—ć«ćÆ惝ćƒŖć‚·ćƒ¼ćØć„ć†ć‚‚ć®ćŒčØ­å®šć§ćć¾ć™ć€‚

ćƒ‡ćƒ•ć‚©ćƒ«ćƒˆć§ćÆ仄äø‹ć®ć„ćšć‚Œć‹ć‚’ä½æ恆恋悒éøęŠžć§ćć¾ć™ć€‚

č©³ć—ćčŖæć¹ć¦ćŖ恄恑恩 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
  • https://docs.python.org/ja/3/library/asyncio-dev.html

惍惃惈ćƒÆćƒ¼ć‚Æ通äæ”

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 ć«ć‚‚ę„Ÿč¬ć€‚

恂悊恌ćØć†ć”ć–ć„ć¾ć—ćŸć€‚

å‚č€ƒ