Share
Embed
Transcript
28 slides
-
私とは • Moriyoshi Koizumi • Twitter @moriyoshit / GitHub @Moriyoshi
• PHPのコミッター (ほぼ廃業) / Goのコントリビュータなど • オープンコレクター (https://open-c.jp/) という会社をやって います -
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 -
黎明期 • 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 -
asyncore (1996-) • Python 1.4? • Sam Rushingによる • コールバックベースのAPI
• 3.6 でdeprecated、PEP 594でdead battery宣告 -
Medusa (1996-) • http://www.nightmare.com/medusa/ • Sam Rushingによる • Python 1.5
(1997/12) 時代の非同期I/Oライブラリ • asyncoreベース • スタンフォードの研究プロジェクト時代のGoogleで使われてい た “google.stanford.edu” • 他にはZopeなど -
Twisted (2002-) • Glyph Lefkowitzによる • コールバックベースのAPI • asyncoreの設計を見直し、幅広いプロトコルのサポート •
商用オンラインゲーム、Buildbotなどに採用 -
Tornado (2009-) • Ben Darnell / Bret Taylorによる • 当初はコールバック
/ 継続渡しベース • のちにジェネレータを使った疑似コルーチンを導入 (2011-) -
eventlet (2008-) / gevent (2009-) • eventlet • Second Lifeを運営するLinden
Labによる • greenletベースの非同期I/Oライブラリ • gevent • Denis Bilenkoによる • Greenletベースの非同期I/Oライブラリ • eventletの改善版として開発 -
Tulip a.k.a. asyncio (2011-) • PEP 3156 • async SIGで開発
• Twistedのプロトコル抽象化の設計を参考に、 PEP 380で導入されたジェネレータの移譲を用いて近代的な設 計にすることを主旨 • Python 3.4で標準モジュール化 -
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? -
Stackless Python (PEP 219; 2000) • このスレッドではコルーチンの対称性についてや、Schemeの call/ccとコルーチンの比較も議論される • Christian
Tismerが議論を進めながら いきなり実装を作ってしまったのがStackless Python • ランタイム自体に変更を加え、コルーチンの実行を可能にした もの (ABIの互換性がない) -
Stackless Python (PEP 219; 2000) • Tasklet • 協調的スレッドで、コルーチンではない (暗黙のスケジューラが存在)
• Channel • Tasklet間のコミュニケーションに使えるキュー -
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() -
Simple Generator (PEP 255, 2001) • ジェネレータの基本文法 • Python 2.2で導入
• Neil Schemenauer / Tim Peters / Magnus Lie Hetlandらによ る • Sather / CLU / Iconの影響に言及 -
Simple Generatorのコード例 def gen(): for i in range(0, 10): yield
i * 2 for i in gen(): print(i) -
Coroutines via Enhanced Generator (PEP 342; 2005) • PEP 288
(Generators Attributes and Exceptions) / PEP 325 (Generators Attributes and Exceptions) の提案を元に、 • yieldを式の中で扱えるように • 呼び出し元からジェネレータの中に値を送れるように • 呼び出し先に例外を返せるように • try-finally節の中でyieldできるように したもの -
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 -
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. -
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) -
Syntax for Delegating to Subgenerator (PEP 380; 2011) • yield
from構文の導入 • 2009年に提案され、asyncioの開発に伴ってGuidoにより承認 -
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] -
asyncio with async / await syntax (PEP 492; 2015) •
PEP 492 • Yury Selivanovによる • C# / ECMAScript 7 stage 3の提案の影響についての言及 • Python 3.5 -
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()) -
asyncio with async / await syntax (PEP 492; 2015) await
foo() i += 1 asyncio.sleep() await foo() i += 1 asyncio.sleep() • メソッドをawaitの呼び出しの単位で細 切りにする • 細切りの単位でジェネレータを進めて いく • async関数の呼び出しはジェネレータ の移譲と同じ イベントループ -
まとめ • Pythonにおけるコルーチンの議論は、ジェネレータの導入以前 から存在していた!!!! • コルーチンの議論を先に推し進めていたのは、 非同期I/Oをコールバックや継続渡しではなく、外部イテレー タ的に実現するという現実的な欲求だった!!!! • 本物*のコルーチンを実装しているのはgreenletだけ!!!!
*先に紹介したStackless PythonのスレッドでTim Petersが言った言葉