pythonコラボレーションによる同時操作の方法の詳細
4559 ワード
この例では、pythonがコラボレーションを使用して同時操作を実現する方法について説明します.皆さんの参考にしてください.具体的には以下の通りです.
きょうてい
コヒーレンスはユーザ状態の軽量レベルスレッドであり、マイクロスレッドとも呼ばれる.
協程は独自のレジスタコンテキストとスタックを持ち、スケジューリング切り替え時にレジスタコンテキストとスタックを他の場所に保存し、切り取ったときに以前に保存したレジスタコンテキストとスタックを復元する.したがって、コプロセッサは、前回の呼び出し時の状態(すなわち、すべてのローカル状態の特定の組合せ)を保持することができ、プロシージャが再入力されるたびに、前回の呼び出しの状態に入ることに相当し、言い換えれば、前回の呼び出し時に論理ストリームの位置に入ることになる.
メリット:スレッドコンテキスト切替を必要としないオーバーヘッド 原子操作ロックおよび同期を必要としないオーバーヘッド 制御フローの切り替えを容易にし、プログラミングモデル を簡略化する.高同時+高拡張性+低コスト:1つのCPUが万以上の協力をサポートするのは問題ではありません.したがって、高同時処理に適しています.
原子操作とは、スレッドスケジューリングメカニズムによって中断されない操作を指す.この操作はいったん開始されると、終了まで実行され、その間にcontext switch(別のスレッドに切り替える)はありません.
原子操作は1つのステップであってもよいし、複数の操作ステップであってもよいが、その順序は乱されてはならないか、または実行部分のみを切断してはならない.全体を原子性の核心と見なす.
欠点:はマルチコア資源を利用することができない:コヒーレンスの本質は単一スレッドであり、単一CPUの複数コアを同時に使用することができず、コヒーレンスはプロセスと協力してマルチCPU上で実行する必要がある.もちろん、cpu密集型アプリケーションでない限り、私たちが日常的に作成しているほとんどのアプリケーションはこの必要はありません. がブロック(Blocking)操作(IOの場合など)を行うと、プログラム 全体がブロックされる.
Geventの使用
geventはpythonの同時フレームワークであり、マイクロスレッドgreenletを核心とし、epollイベントの傍受メカニズムと多くの他の最適化を用いて効率的になる.簡単な例 geventのsleepは制御権を渡すことができ、ネットワークやIOに制限された関数でgeventを使用すると、これらの関数はコラボレーション的にスケジューリングされ、geventの本当の能力が発揮されます.Geventはすべての詳細を処理し、あなたのネットワークライブラリが可能なときにgreenletコンテキストの実行権を暗黙的に渡すことを保証します.
実行結果
running in foo running in bar com back from bar in to foo com back from foo in to bar同期非同期
実行出力
Synchronous: Task 1 done Task 2 done Task 3 done Task 4 done Task 5 done Task 6 done Task 7 done Task 8 done Task 9 done Asynchronous: Task 1 done Task 4 done Task 5 done Task 9 done Task 6 done Task 0 done Task 2 done Task 3 done Task 7 done Task 8 doneコパス をサブクラスの方法で使用する
Greenletクラスをサブクラス化して再ロードできます.runメソッド、マルチスレッドおよびマルチプロセスモジュールのような monkey patchを使用してシステム標準ライブラリ(自動切替協程) を修正する
1つのgreenletがIO操作に遭遇した場合、例えばネットワークにアクセスすると、自動的に他のgreenletに切り替えられ、IO操作が完了するまで待ってから、適切な時に切り替えて実行を継続します.
IO操作は非常に時間がかかるため、プログラムを常に待機状態にし、geventが自動的に協程を切り替えることで、IOを待つのではなくgreenletが常に実行されていることを保証します.
切り替えはIO操作時に自動的に完了するため、geventはPythonが持参したいくつかの標準ライブラリを変更する必要があります.このプロセスは起動時にmonkey patchで完了します.
実行出力
2443 bytes received from https://www.baidu.com/108315 bytes received from https://www.jd.com/231873 bytes received from https://www.qq.com/
3つのネットワーク操作が同時に実行され,終了順序が異なることがわかる.
参照リンク:http://hhkbp2.github.io/gevent-tutorial/
Pythonに関する詳細については、「Pythonプロセスとスレッド操作テクニックの概要」、「Pythonデータ構造とアルゴリズムチュートリアル」、「Python関数使用テクニックの概要」、「Python文字列操作テクニックの概要」、「Python入門と進級経典チュートリアル」、「Python+MySQLデータベースプログラム設計入門チュートリアル」、「Pythonよくあるデータベース操作テクニックの概要」を参照してください.
ここではPythonプログラムの設計に役立つことを願っています.
きょうてい
コヒーレンスはユーザ状態の軽量レベルスレッドであり、マイクロスレッドとも呼ばれる.
協程は独自のレジスタコンテキストとスタックを持ち、スケジューリング切り替え時にレジスタコンテキストとスタックを他の場所に保存し、切り取ったときに以前に保存したレジスタコンテキストとスタックを復元する.したがって、コプロセッサは、前回の呼び出し時の状態(すなわち、すべてのローカル状態の特定の組合せ)を保持することができ、プロシージャが再入力されるたびに、前回の呼び出しの状態に入ることに相当し、言い換えれば、前回の呼び出し時に論理ストリームの位置に入ることになる.
メリット:
原子操作とは、スレッドスケジューリングメカニズムによって中断されない操作を指す.この操作はいったん開始されると、終了まで実行され、その間にcontext switch(別のスレッドに切り替える)はありません.
原子操作は1つのステップであってもよいし、複数の操作ステップであってもよいが、その順序は乱されてはならないか、または実行部分のみを切断してはならない.全体を原子性の核心と見なす.
欠点:
Geventの使用
geventはpythonの同時フレームワークであり、マイクロスレッドgreenletを核心とし、epollイベントの傍受メカニズムと多くの他の最適化を用いて効率的になる.
import gevent
def foo():
print('running in foo')
gevent.sleep(0)
print('com back from bar in to foo')
def bar():
print('running in bar')
gevent.sleep(0)
print('com back from foo in to bar')
#
gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
])
実行結果
running in foo running in bar com back from bar in to foo com back from foo in to bar
import random
import gevent
def task(pid):
gevent.sleep(random.randint(0, 2) * 0.001)
print('Task %s done' % pid)
def synchronous():
for i in range(1, 10):
task(i)
def asynchronous():
threads = [gevent.spawn(task, i) for i in range(10)]
gevent.joinall(threads)
print('Synchronous:')
synchronous()
print('Asynchronous:')
asynchronous()
実行出力
Synchronous: Task 1 done Task 2 done Task 3 done Task 4 done Task 5 done Task 6 done Task 7 done Task 8 done Task 9 done Asynchronous: Task 1 done Task 4 done Task 5 done Task 9 done Task 6 done Task 0 done Task 2 done Task 3 done Task 7 done Task 8 done
Greenletクラスをサブクラス化して再ロードできます.runメソッド、マルチスレッドおよびマルチプロセスモジュールのような
import gevent
from gevent import Greenlet
class Test(Greenlet):
def __init__(self, message, n):
Greenlet.__init__(self)
self.message = message
self.n = n
def _run(self):
print(self.message, 'start')
gevent.sleep(self.n)
print(self.message, 'end')
tests = [
Test("hello", 3),
Test("world", 2),
]
for test in tests:
test.start() #
for test in tests:
test.join() #
1つのgreenletがIO操作に遭遇した場合、例えばネットワークにアクセスすると、自動的に他のgreenletに切り替えられ、IO操作が完了するまで待ってから、適切な時に切り替えて実行を継続します.
IO操作は非常に時間がかかるため、プログラムを常に待機状態にし、geventが自動的に協程を切り替えることで、IOを待つのではなくgreenletが常に実行されていることを保証します.
切り替えはIO操作時に自動的に完了するため、geventはPythonが持参したいくつかの標準ライブラリを変更する必要があります.このプロセスは起動時にmonkey patchで完了します.
import gevent
import requests
from gevent import monkey
monkey.patch_socket()
def task(url):
r = requests.get(url)
print('%s bytes received from %s' % (len(r.text), url))
gevent.joinall([
gevent.spawn(task, 'https://www.baidu.com/'),
gevent.spawn(task, 'https://www.qq.com/'),
gevent.spawn(task, 'https://www.jd.com/'),
])
実行出力
2443 bytes received from https://www.baidu.com/108315 bytes received from https://www.jd.com/231873 bytes received from https://www.qq.com/
3つのネットワーク操作が同時に実行され,終了順序が異なることがわかる.
参照リンク:http://hhkbp2.github.io/gevent-tutorial/
Pythonに関する詳細については、「Pythonプロセスとスレッド操作テクニックの概要」、「Pythonデータ構造とアルゴリズムチュートリアル」、「Python関数使用テクニックの概要」、「Python文字列操作テクニックの概要」、「Python入門と進級経典チュートリアル」、「Python+MySQLデータベースプログラム設計入門チュートリアル」、「Pythonよくあるデータベース操作テクニックの概要」を参照してください.
ここではPythonプログラムの設計に役立つことを願っています.