Python連携(geventモジュール)
5736 ワード
一:はじめに
コヒーレンスはマイクロスレッド、ファイバスレッドとも呼ばれます.英語名Coroutine:コパスはユーザー状態の軽量レベルスレッドです
協程は独自のレジスタコンテキストとスタックを持っている.コンシステントスケジューリング切り替え時には、レジスタコンテキストとスタックを別の場所に保存し、切り取ったときに、前に保存したレジスタコンテキストとスタックを復元します.したがって、次のようになります.
コンシステントは、前回呼び出し時の状態を保持し、前回離れたときの論理ストリームの位置に入ることができる
協力のメリットスレッドコンテキスト切替を必要としないオーバーヘッド 原子操作(スレッドスケジューリング機構によって中断されない操作)のロックおよび同期のオーバーヘッド を必要としない.制御フローの切り替えを容易にし、プログラミングモデル を簡略化する.高同時+高拡張+低成文:1つのCPUが上完の協程をサポートするのは問題ないので、高同時処理 に適しています.
きょうていの欠点マルチコアリソースを利用できない:コプロセッサの本質は単一スレッドであり、マルチCPU上で を実行するにはプロセスと協力する必要がある.がブロック(Blocking)操作(IOの場合など)を行うと、プログラム 全体がブロックされる.
きょうていのじょうけんは、1つの単一スレッドのみで同時 を実現する必要があります.共有データの変更 ロック不要ユーザプログラムに複数の制御フローを自己保存するコンテキストスタック コパスがIO操作に遭遇すると、自動的に他のコパス に切り替える.
yieldを使用したコラボレーション
二:Greenlet
グリーンレットはCで実装されたコラボレーションモジュールで、pythonが持参したyieldに比べて、generatorとして宣言する必要がなく、任意の関数の間で自由に切り替えることができます.
グリーンレットを使用したコラボレーション
三:Gevent
Geventはサードパーティ製のライブラリ(追加で自分でインストールする必要がある)であり、geventによって容易に同時同期または非同期プログラミングを実現することができ、geventで主に使用されるモードはGreenletであり、C拡張モジュールの形式でPythonにアクセスする軽量レベルのコラボレーションである.Greenletはすべてメインプログラムオペレーティングシステムの内部で実行され、コラボレーションスケジューリングされる
geventライブラリを使用したコラボレーション
同期と非同期のパフォーマンスの違い
task関数はGreenlet内部スレッドの
IOブロックに遭遇すると自動的にタスクが切り替わります
geventによる単一スレッドでのマルチソケット同時実行
serverエンド
クライアント側
同時100ソケット接続
コヒーレンスはマイクロスレッド、ファイバスレッドとも呼ばれます.英語名Coroutine:コパスはユーザー状態の軽量レベルスレッドです
協程は独自のレジスタコンテキストとスタックを持っている.コンシステントスケジューリング切り替え時には、レジスタコンテキストとスタックを別の場所に保存し、切り取ったときに、前に保存したレジスタコンテキストとスタックを復元します.したがって、次のようになります.
コンシステントは、前回呼び出し時の状態を保持し、前回離れたときの論理ストリームの位置に入ることができる
協力のメリット
きょうていの欠点
きょうていのじょうけん
yieldを使用したコラボレーション
def consumer(name):
print("--->starting eating baozi...")
while True:
new_baozi = yield
print("[%s] is eating baozi %s" % (name, new_baozi))
def producer():
next(con)
next(con2)
n = 0
while n < 5:
n += 1
con.send(n)
con2.send(n)
print("\033[32;1m[producer]\033[0m is making baozi %s" % n)
if __name__ == '__main__':
con = consumer("c1")
con2 = consumer("c2")
p = producer()
二:Greenlet
グリーンレットはCで実装されたコラボレーションモジュールで、pythonが持参したyieldに比べて、generatorとして宣言する必要がなく、任意の関数の間で自由に切り替えることができます.
グリーンレットを使用したコラボレーション
from greenlet import greenlet
def f1():
print(12)
gr2.switch()
print(34)
gr2.switch()
def f2():
print(56)
gr1.switch()
print(78)
if __name__=='__main__':
gr1 = greenlet(f1)
gr2 = greenlet(f2)
gr1.switch() # ,gevent greenlet ,
# 12
56
34
78
三:Gevent
Geventはサードパーティ製のライブラリ(追加で自分でインストールする必要がある)であり、geventによって容易に同時同期または非同期プログラミングを実現することができ、geventで主に使用されるモードはGreenletであり、C拡張モジュールの形式でPythonにアクセスする軽量レベルのコラボレーションである.Greenletはすべてメインプログラムオペレーティングシステムの内部で実行され、コラボレーションスケジューリングされる
geventライブラリを使用したコラボレーション
import gevent
def func1():
print("func1 running")
gevent.sleep(2) # io
print("switch func1")
def func2():
print("func2 running")
gevent.sleep(1)
print("switch func2")
def func3():
print("func3 running")
gevent.sleep(0.5)
print("func3 done..")
if __name__=='__main__':
gevent.joinall([gevent.spawn(func1),
gevent.spawn(func2),
gevent.spawn(func3),
])
同期と非同期のパフォーマンスの違い
import gevent
def task(pid):
"""
Some non-deterministic task
"""
gevent.sleep(0.5)
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)
if __name__ =='__main__':
print('Synchronous:')
synchronous()
print('Asynchronous:')
asynchronous()
task関数はGreenlet内部スレッドの
gevent.spawn
にカプセル化される.初期化されたgreenletリストは、現在のプロセスをブロックし、所与のgreenletをすべて実行するthreads
関数に渡される配列gevent.joinall
に格納される.実行プロセスは、すべてのgreenletが実行された後にのみ下に進みます. IOブロックに遭遇すると自動的にタスクが切り替わります
from gevent import monkey
monkey.patch_all()
import gevent
from urllib.request import urlopen
def f(url):
print('GET: %s' % url)
resp = urlopen(url)
data = resp.read()
print('%d bytes received from %s.' % (len(data), url))
if __name__=='__main__':
gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
])
geventによる単一スレッドでのマルチソケット同時実行
serverエンド
import sys
import socket
import time
import gevent
from gevent import socket,monkey
monkey.patch_all()
def server(port):
s = socket.socket()
s.bind(('0.0.0.0', port))
s.listen(500)
while True:
cli, addr = s.accept()
gevent.spawn(handle_request, cli)
def handle_request(conn):
try:
while True:
data = conn.recv(1024)
print("recv:", data)
conn.send(data)
if not data:
conn.shutdown(socket.SHUT_WR)
except Exception as ex:
print(ex)
finally:
conn.close()
if __name__ == '__main__':
server(8001)
クライアント側
import socket
HOST = 'localhost' # The remote host
PORT = 8001 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
msg = bytes(input(">>:"),encoding="utf8")
s.sendall(msg)
data = s.recv(1024)
#print(data)
print('Received', repr(data))
s.close()
同時100ソケット接続
import socket
import threading
def sock_conn():
client = socket.socket()
client.connect(("localhost",8001))
count = 0
while True:
#msg = input(">>:").strip()
#if len(msg) == 0:continue
client.send( ("hello %s" %count).encode("utf-8"))
data = client.recv(1024)
print("[%s]recv from server:" % threading.get_ident(),data.decode()) #
count +=1
client.close()
for i in range(100):
t = threading.Thread(target=sock_conn)
t.start()