;コルーチンは、また、マイクロスレッドと呼ばれる細断、英語コルーチン文は、スレッドです:軽量コルーチンをスレッドのユーザー状態です。
また、比較的単純なpython2でコルーチンためのPythonのサポートが、のpython3でフルサポートを開始するだけでなく、コア機能のpython3になるために使用することができ、サードパーティのライブラリが存在し、それは学習の価値があります。
社会の生産プロセス
;コルーチンは、また、マイクロスレッドと呼ばれる細断、英語コルーチン文は、スレッドです:軽量コルーチンをスレッドのユーザー状態です。
コルーチンは独自のスタックを持っているとコンテキストを登録します。コルーチンは、ハンドオーバ、レジスタコンテキストの退避を予定し、別の場所にスタックすると戻って切断した場合、コンテキストは、以前に保存されたレジスタとスタックを復元します。こうして:コルーチンはそれぞれリエントラントの間(すなわち、ローカル状態の全ての特定の組合せ)の最後の呼び出し、、、別の方法で呼状態に入るの等価物として残すことができる。一度離脱を入力にロジックフロー位置に。
コルーチンの利点:
1)あなたは、スレッドのコンテキストスイッチのオーバーヘッドを必要としません
2)ロックとオーバーヘッドなしでアトミック操作を同期させます
3)切り替え制御の流れを容易にするために、簡略化されたプログラミングモデル
4)高い同時実行+拡張+低コスト:サポートコルーチン用CPU万人が問題ではありません。だから、高い並列処理に適しています。
コルーチン短所:
1)マルチコアリソースを活用することができません。コルーチンの性質はシングルスレッドである、それは、複数の核を過ごすことができない、複数のCPU上で実行するために、単一のCPUとのニーズとプロセスをコルーチン
2)(IO)が遮断されたときに、例えば、(ブロッキング)動作は、プログラム全体をブロックします
コルーチンPython2
収率キーワード
:次のようにコードの例であり、消費者モデル-コルーチンためPython2サポートは、次のサンプルコードは、一般的プロデューサー、収率キーワードによって達成されます。
def consumer():
r = ''
while True:
n = yield r
if not n:
continue
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'
def produce(c):
c.next()
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()
if __name__ == '__main__':
c = consumer()
produce(c)
結果:
消費者に注目すると、通過した後、消費者を生成するために、ファンクションジェネレータ(発電機)です。
1)最初の呼び出しのc.next()発生器を起動し、
2)次に、何かの生産一度、消費者を実行するc.send(n)を切り替えることにより、
3)消費者は、プロセスによるメッセージの収率、及び収率によって返された結果を取得します。
4)次のメッセージを生成し続けて、プロセスの結果を得るために消費者を作り出します。
5)c.close()、全プロセスの終わり近くに消費者を生成しないことを決定し生成します。
整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。
如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高。
Python对协程的支持还非常有限,用在generator中的yield可以一定程度上实现协程。虽然支持不完全,但已经可以发挥相当大的威力了。
gevent模块
Python通过yield提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。gevent是第三方库,通过greenlet实现协程,其基本思想是:
当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成。
示例代码如下:
from gevent import monkey; monkey.patch_all()
import gevent
import urllib2
def f(url):
print('GET: %s' % url)
resp = urllib2.urlopen(url)
data = resp.read()
print('%d bytes received from %s.' % (len(data), url))
gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
])
执行结果:
从执行结果可以看到,网站访问的顺序是自动切换的。
gevent优缺
使用gevent,可以获得极高的并发性能,但gevent只能在Unix/Linux下运行,在Windows下不保证正常安装和运行。Python创始人Gvanrossum从来不喜欢Gevent,而是更愿意另辟蹊径的实现asyncio(python3中的异步实现)。
1)Monkey-patching。中文「猴子补丁」,常用于对测试环境做一些hack。Gvanrossum说用它就是”patch-and-pray”,由于Gevent直接修改标准库里面大部分的阻塞式系统调用,包括socket、ssl、threading和 select等模块,而变为协作式运行。但是无法保证在复杂的生产环境中有哪些地方使用这些标准库会由于打了补丁而出现奇怪的问题,那么只能祈祷(pray)了。
2)其次,在Python之禅中明确说过:「Explicit is better than implicit.」,猴子补丁明显的背离了这个原则。
3)第三方库支持。得确保项目中用到其他用到的网络库也必须使用纯Python或者明确说明支持Gevent,而且就算有这样的第三方库,也需要担心这个第三方库的代码质量和功能性。
4)Greenlet不支持Jython和IronPython,这样就无法把gevent设计成一个标准库了。
之前是没有选择,很多人选择了Gevent,而现在明确的有了更正统的、正确的选择:asyncio(下一节会介绍)。所以建议大家了解Gevent,拥抱asyncio。
另外,如果知道现在以及未来使用Gevent不会给项目造成困扰,那么用Gevent也是可以的。
Python3中的协程
Gvanrossum希望在Python 3 实现一个原生的基于生成器的协程库,其中直接内置了对异步IO的支持,这就是asyncio,它在Python 3.4被引入到标准库。
下面将简单介绍asyncio的使用:
1)event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
2)coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
3)タスクタスク:状態は、様々なタスクを含むことを特徴とする請求コルーチンオブジェクトは、タスクがコルーチンにさらにカプセル化されて、ネイティブ関数が中断されてもよいです。
4)将来:将来の結果にガイドまたは行わないタスクを実行します。それとタスクの間には本質的な違いはありません
5)非同期/のawaitキーワード:python3.5キーワードは非同期コルーチンを定義し、コルーチンを定義し、非同期呼び出しインターフェースを遮断懸架する待ちます。
次のようにコード例は以下のとおりです。
import asyncio
import time
now = lambda: time.time()
async def do_some_work(x):
print('Waiting: {}s'.format(x))
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
async def main():
coroutine1 = do_some_work(1)
coroutine2 = do_some_work(5)
coroutine3 = do_some_work(3)
tasks = [
asyncio.ensure_future(coroutine1),
asyncio.ensure_future(coroutine2),
asyncio.ensure_future(coroutine3)
]
done, pending = await asyncio.wait(tasks)
for task in done:
print('Task ret: ', task.result())
start = now()
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(main())
try:
loop.run_until_complete(task)
print('TIME: ', now() - start)
except KeyboardInterrupt as e:
print(asyncio.Task.all_tasks())
print(asyncio.gather(*asyncio.Task.all_tasks()).cancel())
loop.stop()
loop.run_forever()
finally:
loop.close()
結果:
私たちは、プログラムの実行時間が最も長い待機時間が優先するものである見ることができます。
使用非同期コルーチンオブジェクトはのawaitを使用して定義することができる収率で発生ように、関数は制御を可能にする、時間のかかる操作のために中断することができます。コルーチンの出会いが待っています、イベントループは、他のコルーチンも中断または終了するまで他のコルーチンの実装を共同推進し、次のコルーチンを実行一時停止します。そのようなネットワーク要求、ファイルの読み込みなどの一般的にいくつかの時間のかかる操作IO操作、。私たちは、IO操作をシミュレートするasyncio.sleep関数を使用します。目的は、非同期IO操作のこれらのコルーチンをさせることです。
Asyncioののpython3内蔵ライブラリ強力ですが、上記だけの簡単な使用方法のasyncioあり、それはについての学習の価値がある、興味を持っています!