Pythonのエレガントな使用

10190 ワード

コプロセッサ(Coroutine)は、プログラマがコードにスケジューリングを表示します.(プロセスとスレッドはオペレーティングシステムによってスケジューリングされ、スレッドはオペレーティングシステムのスケジューリングの最小単位である).
前の記事を見て、スレッドタスクがIOブロックされた後、オペレーティングシステムがスレッドを切り替え、この切り替えは時間とリソースを浪費することを知っているはずです.一方、コヒーレンスは、単一のスレッドで同時に実行される複数のタスクであり、実行中のコヒーレンスタスクがブロックされた後、直ちに他の準備完了ステータスのコヒーレンスタスクに切り替えて実行します.これにより、ブロックのためにスレッドがオペレーティングシステムに切り替えられることが大幅に減少します.協程の切替はプログラムレベルに属し、非常に迅速で、オンライン文には完全にプログラマーがコードに管理を表示し、切替速度が極めて速いため、スレッド切替の浪費資源を減らした.
協力の利点:
  • コモンのスイッチングオーバーヘッドは小さく、より軽量級の
  • GILの存在により,単一スレッド内で同時
  • を実現する.
    協力の欠点:
  • は、複数のCPUを利用することができない(従って、実際の使用では、一般的にはマルチプロセス+コモンシップ)
  • .
    Pythonのyield
    yieldは関数をジェネレータとして構築します.yieldを使用すると、コラボレーションの簡単な実現ができます.タスクでジェネレータを呼び出すと、現在の実行タスクはジェネレータに切り替えてデータを取得し、データを取得してから前の実行タスクに戻ります.
    yieldに関連する2つの一般的な方法があります.
  • next():関数を実行して次のyield
  • を見つけます.
  • send():yieldにデータを送信し、コードを実行して次のyield
  • を見つけます.
    def consumer():
        while True:
            print('     yield')
            x = yield
            print('     :', x)
    
    
    if __name__ == "__main__":
        c = consumer()
        next(c) #        yield
        next(c) #    yield   ,        yield
        c.send(1) #   yield   1,            yield
        c.send(2) #   yield   2,            yield
    

    実行結果:
    すぐにyieldに実行してデータを処理しました:Noneはすぐにyieldに実行してデータを処理しました:1すぐにyieldに実行してデータを処理しました:2すぐにyieldに実行します
    もちろん、上記の使い方にはyieldの正常なジェネレータの使い方もあります.
    def consumer():
        for i in range(6):
            yield i
    
    
    if __name__ == "__main__":
        for i in consumer():
            print(i**2)
        
        #      next
        #           
        c = consumer() 
        print(next(c))
        print(next(c))
        print(next(c))
        #           ,      
        print(next(c))
    
    

    実行結果:
    0 1 4 0 1 2 Traceback (most recent call last): File “markdown/test.py”, line 20, in print(next©) StopIteration
    greenlet
    greenletはpythonにおけるコラボレーション実装の1つを提供する.最外層は呼び出しの初期タスクであり,内層タスクは各greenletである.コパスを作成し、それらの間をジャンプできます.
    greenlet協程でのジャンプはすべて明示的である:1つのgreenlet(g 1と呼ばれる)は別のgreenlet(g 2と呼ばれる)にジャンプすることを選択し、これはg 1を一時停止させ、g 2は切り替えまたは実行が完了するまで実行を開始し、実行が完了すると自動的にg 1に切り替えられ、g 1は実行を継続する(切り替えが完了するとステータスが保存される).
    グリーンレットでコパスに切り替えるには、グリーンレットに対して初めてグリーンレットを実行する場合にswitchメソッドを使用する必要がある.switch()の場合はパラメータを渡す必要があり、後続のswitchではパラメータを渡さない(パスしても無効)
    from greenlet import greenlet
    
    #                    
    
    def eat(user):
        print('%s eat apple' % user)
        g2.switch('Dolphin')  # 3
        print('%s eat banane' % user)
        g2.switch()
    
    
    def sleep(user):
        print('%s is sleeping 1' % user)
        g1.switch("Jary")
        print('%s is sleeping 2' % user)
    
    
    if __name__ == "__main__":
        g1 = greenlet(eat)
        g2 = greenlet(sleep)
    
        g1.switch('Dolphin')
    

    出力結果:
    Dolphin eat apple Dolphin is sleeping 1 Dolphin eat banane Dolphin is sleeping 2
    greenletはgeneratorと比較してswitchを提供し、コヒーレンスを切り替えるのが便利ですが、すべてのコヒーレンスは私たちが手動でスケジューリングするのは友好的ではありません.コンコースの間で渋滞自動スケジューリングに遭遇できたらありがたいですね~
    そこで、Geventは七色の祥雲に乗って来ました~
    Gevent
    Geventはgreenletをパッケージしたサードパーティ製のライブラリで、threadingのようにコラボレーションしたり自動スケジューリングしたりすることができ、geventを通じて同時同期や非同期プログラミングを簡単に実現することができます.
    gevent.の使用spawn起動コヒーレンスはgreenletの手動切替とは異なります.gevent.の使用spawnが作成したコヒーレンスは、実行を待つ準備状態に入ります.
    すでに一般的なコヒーレンスでは、プライマリ・スレッドが終了しても実行が完了していない可能性があります.プライマリ・スレッドでjoin待機期間を使用して実行が完了するか、gevent.を使用します.joinall()は複数のコヒーレンスを待つ.
    geventコンシステントでは、デフォルトではgevent定義のブロックのみが認識されます(たとえば、gevent.sleep()).time.sleep()、open()、ネットワークリクエストというブロックは無視されます.パッチを適用することで解決できます.
    from gevent import monkey
    
    #       time.sleep()、open()、        gevent      
    monkey.patch_all()
    
    #             
    from gevent import monkey;monkey.patch_all()
    

    https://www.cnblogs.com/russellyoung/p/python-zhi-xie-cheng.html