Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Detailing Python's Coroutine out of History

Detailing Python's Coroutine out of History

Avatar for Moriyoshi Koizumi

Moriyoshi Koizumi

May 30, 2019
Tweet

More Decks by Moriyoshi Koizumi

Other Decks in Technology

Transcript

  1. 私とは • Moriyoshi Koizumi • Twitter @moriyoshit / GitHub @Moriyoshi

    • PHPのコミッター (ほぼ廃業) / Goのコントリビュータなど • オープンコレクター (https://open-c.jp/) という会社をやって います
  2. Timeline (199x-2020) 1998 2018 2000 2002 2004 2006 2008 2010

    2012 2014 2016 2020 XMLHTTPRequest Medusa Safari (2003) The C10K problem (1999) Twisted Tornado C# 5.0 Python 1.5.2 Twitter ES7 async/await async / await (PEP 492) Tulip aka asyncio (PEP 3156) greenlet Stackless Python (PEP 219) meinheld gevent Enhanced Generator yield from Flickr Hack
  3. 黎明期 • selectモジュール • おそらくPython 0.9.8 (1993/1) で入った https://hg.python.org/cpython-fullhistory/rev/a4793ae26682 •

    (参考) threadモジュール • おそらくPython 0.9.8 (1993/1) で入った https://hg.python.org/cpython-fullhistory/rev/72aceed365d4
  4. Medusa (1996-) • http://www.nightmare.com/medusa/ • Sam Rushingによる • Python 1.5

    (1997/12) 時代の非同期I/Oライブラリ • asyncoreベース • スタンフォードの研究プロジェクト時代のGoogleで使われてい た “google.stanford.edu” • 他にはZopeなど
  5. Tornado (2009-) • Ben Darnell / Bret Taylorによる • 当初はコールバック

    / 継続渡しベース • のちにジェネレータを使った疑似コルーチンを導入 (2011-)
  6. eventlet (2008-) / gevent (2009-) • eventlet • Second Lifeを運営するLinden

    Labによる • greenletベースの非同期I/Oライブラリ • gevent • Denis Bilenkoによる • Greenletベースの非同期I/Oライブラリ • eventletの改善版として開発
  7. Tulip a.k.a. asyncio (2011-) • PEP 3156 • async SIGで開発

    • Twistedのプロトコル抽象化の設計を参考に、 PEP 380で導入されたジェネレータの移譲を用いて近代的な設 計にすることを主旨 • Python 3.4で標準モジュール化
  8. Stackless Python (PEP 219; 2000) Sam Rushingの1999年のメール: Subject: ‘stackless’ python?

    Date: Thu May 13, 1999 I'm not sure if this has been brought up before in other forums, but has there been discussion of separating the Python and C invocationstacks, (i.e., removing recursive calls to the intepreter) tofacilitate coroutines or first-class continuations?
  9. Stackless Python (PEP 219; 2000) • このスレッドではコルーチンの対称性についてや、Schemeの call/ccとコルーチンの比較も議論される • Christian

    Tismerが議論を進めながら いきなり実装を作ってしまったのがStackless Python • ランタイム自体に変更を加え、コルーチンの実行を可能にした もの (ABIの互換性がない)
  10. Stackless Pythonのコード例 import stackless @stackless.tasklet def ping(c1, c2): v =

    c2.receive() print("ping received {}".format(v)) c1.send(v + 1) @stackless.tasklet def pong(c1, c2): v = c1.receive() print("pong received {}".format(v)) c2.send(v + 1) c1 = stackless.channel() c2 = stackless.channel() ping(c1, c2) pong(c1, c2) c1.send(1) stackless.run()
  11. Simple Generator (PEP 255, 2001) • ジェネレータの基本文法 • Python 2.2で導入

    • Neil Schemenauer / Tim Peters / Magnus Lie Hetlandらによ る • Sather / CLU / Iconの影響に言及
  12. Coroutines via Enhanced Generator (PEP 342; 2005) • PEP 288

    (Generators Attributes and Exceptions) / PEP 325 (Generators Attributes and Exceptions) の提案を元に、 • yieldを式の中で扱えるように • 呼び出し元からジェネレータの中に値を送れるように • 呼び出し先に例外を返せるように • try-finally節の中でyieldできるように したもの
  13. Coroutines via Enhanced Generator (PEP 342; 2005) def ping(): v

    = yield pong_g print("ping received {}".format(v)) pong_g.send(v + 1) def pong(): v = yield ping_g print("pong received {}".format(v)) pong_g.send(v + 1) ping_g = ping() pong_g = pong() next(ping_g) next(pong_g) ping_g.send(1) ping received 1 pong received 2 Traceback (most recent call last): File "test.py", line 17, in <module> ping_g.send(1) File "test.py", line 4, in ping pong_g.send(v + 1) File "test.py", line 10, in pong pong_g.send(v + 1) ValueError: generator already executing
  14. greenlet (2006) • Alexey Borzenkovによる • Stackless Pythonは処理系自体を置き換えたもの • greenletは標準のPythonの一パッケージとして扱える

    • Stackless Pythonは本物のコルーチンを実装できるにもかかわ らず、コルーチンとしてtaskletを扱えるAPIを提供していな かった →greenletの開発のモチベーションの一つ A “greenlet”, on the other hand, is a still more primitive notion of micro-thread with no implicit scheduling; coroutines, in other words. This is useful when you want to control exactly when your code runs.
  15. greenlet (2006) import greenlet @greenlet.greenlet def ping(v): while True: print("ping

    received {}".format(v)) v = pong.switch(v + 1) @greenlet.greenlet def pong(v): while True: print("pong received {}".format(v)) v = ping.switch(v + 1) ping.switch(0)
  16. Syntax for Delegating to Subgenerator (PEP 380; 2011) • yield

    from構文の導入 • 2009年に提案され、asyncioの開発に伴ってGuidoにより承認
  17. Syntax for Delegating to Subgenerator (PEP 380; 2011) def m():

    yield from sub(1) yield from sub(2) def sub(c): for i in range(3): yield c * I print(list(m())) [0, 1, 2, 0, 2, 4]
  18. asyncio with async / await syntax (PEP 492; 2015) •

    PEP 492 • Yury Selivanovによる • C# / ECMAScript 7 stage 3の提案の影響についての言及 • Python 3.5
  19. asyncio with async / await syntax (PEP 492; 2015) import

    asyncio c = 0 async def foo(): global c c += 1 asyncio.sleep(1) return c async def bar(): print(await foo()) print(await foo()) print(await foo()) asyncio.get_event_loop().run_until_complete(bar())
  20. asyncio with async / await syntax (PEP 492; 2015) await

    foo() i += 1 asyncio.sleep() await foo() i += 1 asyncio.sleep() • メソッドをawaitの呼び出しの単位で細 切りにする • 細切りの単位でジェネレータを進めて いく • async関数の呼び出しはジェネレータ の移譲と同じ イベントループ