ホームページ  >  記事  >  バックエンド開発  >  Pythonのコルーチンを詳しく解説(例付き)

Pythonのコルーチンを詳しく解説(例付き)

不言
不言転載
2018-10-13 16:31:012921ブラウズ

この記事では、Python のコルーチンについて詳しく説明します (例付き)。一定の参考価値があります。必要な友人は参照できます。お役に立てれば幸いです。

コルーチン。マイクロスレッドおよびファイバーとも呼ばれます。英語名 Coroutine
Coroutine はサブプログラムのように見えますが、実行中にサブプログラム内で中断し、他のサブプログラムの実行に切り替え、適切なタイミングで戻って実行を継続できます。

最大の利点は、コルーチンの実行効率が非常に高いことです。サブルーチンの切り替えはスレッド切り替えではなく、プログラム自身で制御するため、スレッド切り替えのオーバーヘッドが発生せず、マルチスレッドと比較して、スレッド数が多いほど、コルーチンのパフォーマンス上の利点が顕著になります。
2 番目に大きな利点は、スレッドが 1 つしかないため、マルチスレッドのロック機構が必要なく、同時に変数を書き込んでも競合が発生しないことです。共有リソースはロックせずにコルーチン内で制御されます。 、ステータスのみを決定する必要があるため、実行します。マルチスレッドよりも効率がはるかに高くなります。
コルーチンはスレッドで実行されるため、マルチコアCPUを使用するにはどうすればよいですか?最もシンプルな方法はマルチプロセスコルーチンであり、複数のコアを活用するだけでなく、コルーチンの高効率性を最大限に発揮し、非常に高いパフォーマンスを実現できます。

yield はコルーチンを実装します

Python のコルーチンのサポートはまだ非常に限定的ですが、ジェネレーターで使用される Yield はある程度までコルーチンを実装できます。サポートは完全ではありませんが、すでにかなりの力を発揮できます。

import threading
import time
def producer(c):
    c.__next__()
    n=0
    while n c.send(n) --> n更新
        n = yield r
        if not n:
            break
        print('[消费者]正在调用第%s条数据' %(n))
        time.sleep(1)
        r = 'This is ok!'

if __name__=='__main__':
    print(threading.current_thread())   
    print(threading.active_count())     #查看当前进行的线程
    c = consumer()
    producer(c)     #函数中有yield, 返回值为生成器;
    print(threading.active_count()) #1

Pythonのコルーチンを詳しく解説(例付き)

gevent ライブラリはコルーチンを実装します

Python は yield を通じてコルーチンの基本的なサポートを提供しますが、完全ではありません。サードパーティの gevent は、Python の比較的完全なコルーチン サポートを提供します。

gevent は、グリーンレットを通じてコルーチンを実装するサードパーティ ライブラリです。基本的な考え方は次のとおりです:
グリーンレットがネットワークへのアクセスなどの IO 操作に遭遇すると、自動的に他のグリーンレットに切り替わり、IO 操作が完了するまで待機します。が完了したら、必要に応じてスイッチを戻して実行を続行します。 IO 操作には非常に時間がかかるため、プログラムは待機状態になることがよくありますが、gevent がコルーチンを自動的に切り替えることで、Greenlet が IO を待たずに常に実行されることが保証されます。

切り替えは IO 操作中に自動的に完了するため、gevent は Python 付属の標準ライブラリの一部を変更する必要がありますが、このプロセスは起動時にモンキー パッチによって完了します。

複数のコルーチンによって実行されるタスクに IO 操作または待機がない場合、コルーチンは交互ではなく順次に実行されます。
複数のコルーチンによって実行されるタスクに IO 操作または待機があると想定され、コルーチンは実行されます交互に;

#没有等待
import gevent
from gevent import monkey
monkey.patch_all()
def job(n):
    for i in range(n):
        print(gevent.getcurrent(),i)

def mian():
    g1 = gevent.spawn(job,1)
    g2 = gevent.spawn(job,2)
    g3 = gevent.spawn(job,3)
    gevent.joinall([g1,g2,g3])
    print('协程执行任务结束...')

if __name__=="__main__":
    mian()

Pythonのコルーチンを詳しく解説(例付き)

"""
#有等待
import time
from gevent import  monkey
monkey.patch_all()

import  gevent
def job(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        time.sleep(1)

def main1():
    # 创建三个协程, 并让该协程执行job任务
    g1 = gevent.spawn(job, 2)
    g2 = gevent.spawn(job, 3)
    g3 = gevent.spawn(job, 2)
    # 等待所有的协程执行结束, 再执行主程序;
    gevent.joinall([g1, g2, g3])
    print("任务执行结束.....")

main1()

Pythonのコルーチンを詳しく解説(例付き)

コルーチンで比較実験を行います。コルーチンと、スレッド

を使用したスレッドによって費やされた時間ですが、これは有益ではありません。

import time
import gevent   #导入协程
from gevent import monkey
from urllib.request import urlopen  #连接网络
from mytimeit import timeit #导入计算时间的装饰器
from concurrent.futures import ThreadPoolExecutor   #导入线程池

def get_len_url(url):
    with urlopen(url) as u_conn:
        data = u_conn.read()
#       print('%s该网页共%s字节' %(url,len(data)))
urls = ['http://httpbin.org', 'http://example.com/']*100

@timeit
def coroutineall():
    gevents = [gevent.spawn(get_len_url,url) for url in urls]
    gevent.joinall(gevents)

@timeit
def threadall():
    with ThreadPoolExecutor(max_workers=100) as thpool:
        thpool.map(get_len_url,urls)
if __name__=="__main__":
    coroutineall()
    threadall()

Pythonのコルーチンを詳しく解説(例付き)

以上がPythonのコルーチンを詳しく解説(例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。