day38
スレッドキュー
マルチスレッドは、リソースをつかみます
唯一のシリアルましょう - ミューテックスを使用します
スレッドキュー
- キュー - 先入れ先出し(FIFO)
import queue
q = queue.Queue(3)
q.put(1)
q.put(2)
q.put(3)
# q.put(4) # 阻塞等其他进程或者线程来拿
print(q.get())
print(q.get())
print(q.get())
# print(q.get(block=False)) # 没有值就直接报错
# q.get(timeout=2) # 阻塞2s,还没有值直接报错
- スタック - (LIFO)の後に進みました
import queue
q = queue.LifoQueue(4)
q.put(1)
q.put(2)
q.put("alex")
q.put("太白")
print(q.get())
print(q.get())
print(q.get())
print(q.get())
结果:
太白
alex
2
1
- プライオリティキュー - 自分の優先順位を設定
import queue
q = queue.PriorityQueue(4)
q.put((5, "元宝"))
q.put((-2, "狗狗"))
q.put((0, "2李业"))
q.put((0, "1刚哥"))
print(q.get())
print(q.get())
print(q.get()) # 数字越小就先出去,相同数字按照asill码来排序
イベントイベント
オープン2つのスレッドが、1つのスレッドの結合を増加させる他のスレッドは、2つのスレッドを実行トリガー、ステージの中央に走ります
バージョン
from threading import Thread
from threading import current_thread
import time
flag = False
def check():
print(f"{current_thread().name} 监测服务器是否开启。。。")
time.sleep(3)
global flag
flag = True
print("服务器已经开启。。。")
def connect():
while 1:
print(f"{current_thread().name} 等待连接。。。")
time.sleep(0.5)
if flag:
print(f"{current_thread().name} 连接成功。。。")
break
t1 = Thread(target=check)
t2 = Thread(target=connect)
t1.start()
t2.start()
バージョン2 - イベントのイベント
from threading import Thread
from threading import current_thread
from threading import Event
import time
event = Event()
def check():
print(f"{current_thread().name} 监测服务器是否开启。。。")
time.sleep(3)
# print(event.is_set())
event.set()
# print(event.is_set())
print("服务器已经开启。。。")
def connect():
print(f"{current_thread().name} 等待连接。。。")
event.wait() # 阻塞直到event.set() 方法之后
# event.wait(1) # 只阻塞1s,1s之后如果还没有进行set 直接进行下一步操作
print(f"{current_thread().name} 连接成功。。。")
t1 = Thread(target=check)
t2 = Thread(target=connect)
t1.start()
t2.start()
要件:、それは接続が成功であることを示している別のスレッドが開始するかどうかを決定するために、スレッド・サーバの監視を開始するかどうかを3倍以上あれば、このスレッドに一度だけ3回、1秒を接続しようと、まだ接続が成功し、それは接続に失敗した示し
from threading import Thread
from threading import current_thread
from threading import Event
import time
event = Event()
def check():
print(f"{current_thread().name} 监测服务器是否开启")
time.sleep(2)
event.set()
def connect():
print(f"{current_thread().name} 等待连接,,,")
for i in range(3):
event.wait(1)
if event.is_set():
print("服务器已经开启")
print(f"{current_thread().name} 连接成功")
break
else:
print(f"{current_thread().name} 连接失败{i+1}次")
t1 = Thread(target=check)
t2 = Thread(target=connect)
t1.start()
t2.start()
コルーチン
コルーチン詳細:https://www.cnblogs.com/jin-xin/articles/11245654.html
スレッド同時処理タスク
- シリアル:実行が完了した後に、タスクを実行中のスレッド、次のタスク
- パラレル:CPU、複数の複数のタスクを実行し、CPU 4は、4つのタスクを実行します
- 同時実行:同時に複数のタスクを実行するには、CPUが実行ように見えます
同時本当のコア:保留CPU +スイッチ
マルチスレッドの並行処理:3スレッド10タスクのタスク処理スレッド1経験ブロッキング、他のスレッドに切り替えるために、オペレーティングシステムによってCPUなら
スレッド処理タスクを同時にできますか??
3つのタスクを処理する1つのスレッド
シングルCPU:10個のタスクは、私はあなたにこれらの10個のタスクの同時実行を与えてみましょう:
- 方法1:オペレーティングシステムが保留+に切り換えられ、複数のプロセスの同時実行を開き
- 第二の方法:複数のスレッドの同時実行を開いて、オペレーティングシステムが保留+に切り替えられました
- 三つの方法:オープン同時コルーチンの実行、独自のCPUと制御プログラムの3つのタスクが+ホールドの間で前後に切り替えるには
3の詳細説明:コルーチンオペレーティング・システムは、あなたがこのスレッドを実行するCPUが検討されているように、彼は、オペレーティングシステムに目がくらんで非常に高速な、目を切り替える(コルーチン)
コルーチン最良の方法は、なぜですか?
利点:
- 小さなオーバーヘッド
- もっと早く走ります
- コルーチンは、長い間、私はちょうどプログラム内のすべてのタスクを実行するCPUを占有します
短所:
自然コルーチンはシングルスレッドであるマルチコアを使用することができない、プログラムは、よりオープンなプロセスは、各プロセス内のオープン複数のスレッドであってもよく、各コルーチンオープンスレッド
IO集約型、コンピューティング集約型の良いまたはシリアルとコルーチン良い取引
コルーチンとは何ですか?
シングルスレッド同時処理タスクの複数+プログラム制御保留状態コルーチンを切り替えます
コルーチン機能
- それは唯一のシングルスレッドで同時に実施されなければなりません
- ロックすることなく共有データを変更します
- ユーザプログラムコンテキスト複数の制御フローのそのスタックを保存(保持状態)
- IO遭遇コルーチンは自動的に他のタスクに切り替わります
仕事
一般的に、我々はすべて、最高の結果を達成するために、同時、並行性を達成するためのプロセス+スレッド+コルーチンの方法を作業している場合は4コアのCPU、一般的に5つのプロセス、20個のスレッドのそれぞれ(5回からCPU番号)、各スレッドは、大規模なページをクロールするとき、我々は同時コルーチンを達成するために使用することができたときに、ネットワークの遅延時間を待つ500コルーチンを、再生することができます。一般4CPU同時機械の最大数である同時= 5 * 20 * 500 = 50000同時の数、。nginxの負荷分散は、通常、両方の操作がブロッキング操作を有する計算され、この20タスクコードでシングルスレッド5ワットであり、最大荷重は、我々は、ブロッキング時間の使用に、タスク1の実装でブロッキング体験することができ2タスクを実行します。。。。だから、Geventモジュールを使用して効率を改善するためです。
切り替える前に学ぶための何のコードがありません。
def func1():
print("in func1")
def func2():
print("in func2")
func1()
print("end")
func2()
+ホールドスイッチ:IOは、スイッチへのイニシアチブを取ることはありませ会いました
def gen():
while 1:
yield 1
print(333)
def func():
obj = gen()
for i in range(10):
print(next(obj))
func()
基礎となる技術のコルーチンをgreenlet--
from greenlet import greenlet
import time
def eat(name):
print(f"{name} eat 1") # 2
g2.switch("taibai") # 3
# time.sleep(3)
print(f"{name} eat 2") # 6
g2.switch() # 7
def play(name):
print(f"{name} play 1") # 4
g1.switch() # 5
print(f"{name} play 2") # 8
g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch("taibai") # 切换到eat任务 1
コルーチン低いバージョン
- アナログブロック
import gevent
import time
from threading import current_thread
def eat(name):
print(f"{name} eat 1") # 2
print(current_thread().name) # 3
gevent.sleep(2)
# time.sleep(2)
print(f"{name} eat 2") # 7
def play(name):
print(f"{name} play 1") # 4
print(current_thread().name) # 5
gevent.sleep(1)
# time.sleep(1)
print(f"{name} play 2") # 6
g1 = gevent.spawn(eat, "egon")
g2 = gevent.spawn(play, "egon")
print(f"主{current_thread().name}") # 1
g1.join()
g2.join()
结果:
主MainThread
egon eat 1
MainThread
egon play 1
MainThread
egon play 2
egon eat 2
- 本当の閉塞
import gevent
import time
from threading import current_thread
def eat(name):
print(f"{name} eat 1") # 2
print(current_thread().name) # 3
# gevent.sleep(2)
time.sleep(2)
print(f"{name} eat 2") # 4
def play(name):
print(f"{name} play 1") # 5
print(current_thread().name) # 6
# gevent.sleep(1)
time.sleep(1)
print(f"{name} play 2") # 7
g1 = gevent.spawn(eat, "egon")
g2 = gevent.spawn(play, "egon")
print(f"主{current_thread().name}") # 1
g1.join()
g2.join()
结果:
主MainThread
egon eat 1
MainThread
egon eat 2
egon play 1
MainThread
egon play 2
最終版
import gevent
import time
from gevent import monkey
monkey.patch_all() # 打补丁:将下面所有任务的阻塞都打上标记
def eat(name):
print(f"{name} eat 1") # 1
time.sleep(2)
print(f"{name} eat 2") # 4
def play(name):
print(f"{name} play 1") # 2
time.sleep(1)
print(f"{name} play 2") # 3
g1 = gevent.spawn(eat, "egon")
g2 = gevent.spawn(play, "egon")
# g1.join()
# g2.join()
gevent.joinall([g1, g2])
结果:
egon eat 1
egon play 1
egon play 2
egon eat 2
コルーチンアプリケーション
爬虫
from gevent import monkey;monkey.patch_all()
import gevent
import requests
import time
def get_page(url):
print('GET: %s' %url)
response=requests.get(url)
if response.status_code == 200:
print('%d bytes received from %s' %(len(response.text),url))
start_time=time.time()
gevent.joinall([
gevent.spawn(get_page,'https://www.python.org/'),
gevent.spawn(get_page,'https://www.yahoo.com/'),
gevent.spawn(get_page,'https://github.com/'),
])
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
结果:
GET: https://www.python.org/
GET: https://www.yahoo.com/
GET: https://github.com/
48919 bytes received from https://www.python.org/
87845 bytes received from https://github.com/
515896 bytes received from https://www.yahoo.com/
run time is 2.729017734527588
同時シングルスレッドソケットによって達成Gevent(gevent輸入サルから、インポートはソケットモジュールmonkey.patch_all()の前に配置する必要があり、そうでなければソケットブロッキングgevent認識されていません)
経過ネットワーク要求時間遅延時間の複数
サーバ
from gevent import monkey;monkey.patch_all()
from socket import *
import gevent
#如果不想用money.patch_all()打补丁,可以用gevent自带的socket
# from gevent import socket
# s=socket.socket()
def server(server_ip,port):
s=socket(AF_INET,SOCK_STREAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind((server_ip,port))
s.listen(5)
while True:
conn,addr=s.accept()
gevent.spawn(talk,conn,addr)
def talk(conn,addr):
try:
while True:
res=conn.recv(1024)
print('client %s:%s msg: %s' %(addr[0],addr[1],res))
conn.send(res.upper())
except Exception as e:
print(e)
finally:
conn.close()
if __name__ == '__main__':
server('127.0.0.1',8080)
クライアント
from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
msg=input('>>: ').strip()
if not msg:continue
client.send(msg.encode('utf-8'))
msg=client.recv(1024)
またはマルチスレッド複数のクライアント、サービスの上端をお願いすることは問題ありません
from threading import Thread
from socket import *
import threading
def client(server_ip,port):
c=socket(AF_INET,SOCK_STREAM) #套接字对象一定要加到函数内,即局部名称空间内,放在函数外则被所有线程共享,则大家公用一个套接字对象,那么客户端端口永远一样了
c.connect((server_ip,port))
count=0
while True:
c.send(('%s say hello %s' %(threading.current_thread().getName(),count)).encode('utf-8'))
msg=c.recv(1024)
print(msg.decode('utf-8'))
count+=1
if __name__ == '__main__':
for i in range(500):
t=Thread(target=client,args=('127.0.0.1',8080))
t.start()
別のコルーチンモジュールasyncio
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# import asyncio
# 起一个任务.
# async def demo(): # 协程方法
# print('start')
# await asyncio.sleep(1) # 阻塞
# print('end')
# loop = asyncio.get_event_loop() # 创建一个事件循环
# loop.run_until_complete(demo()) # 把demo任务丢到事件循环中去执行
# 启动多个任务,并且没有返回值
# async def demo(): # 协程方法
# print('start')
# await asyncio.sleep(1) # 阻塞
# print('end')
#
# loop = asyncio.get_event_loop() # 创建一个事件循环
# wait_obj = asyncio.wait([demo(),demo(),demo()])
# loop.run_until_complete(wait_obj)
# 启动多个任务并且有返回值
# async def demo(): # 协程方法
# print('start')
# await asyncio.sleep(1) # 阻塞
# print('end')
# return 123
#
# loop = asyncio.get_event_loop()
# t1 = loop.create_task(demo())
# t2 = loop.create_task(demo())
# tasks = [t1,t2]
# wait_obj = asyncio.wait([t1,t2])
# loop.run_until_complete(wait_obj)
# for t in tasks:
# print(t.result())
# 谁先回来先取谁的结果
# import asyncio
# async def demo(i): # 协程方法
# print('start')
# await asyncio.sleep(10-i) # 阻塞
# print('end')
# return i,123
#
# async def main():
# task_l = []
# for i in range(10):
# task = asyncio.ensure_future(demo(i))
# task_l.append(task)
# for ret in asyncio.as_completed(task_l):
# res = await ret
# print(res)
#
# loop = asyncio.get_event_loop()
# loop.run_until_complete(main())
# import asyncio
#
# async def get_url():
# reader,writer = await asyncio.open_connection('www.baidu.com',80)
# writer.write(b'GET / HTTP/1.1\r\nHOST:www.baidu.com\r\nConnection:close\r\n\r\n')
# all_lines = []
# async for line in reader:
# data = line.decode()
# all_lines.append(data)
# html = '\n'.join(all_lines)
# return html
#
# async def main():
# tasks = []
# for url in range(20):
# tasks.append(asyncio.ensure_future(get_url()))
# for res in asyncio.as_completed(tasks):
# result = await res
# print(result)
#
#
# if __name__ == '__main__':
# loop = asyncio.get_event_loop()
# loop.run_until_complete(main()) # 处理一个任务
# python原生的底层的协程模块
# 爬虫 webserver框架
# 题高网络编程的效率和并发效果
# 语法
# await 阻塞 协程函数这里要切换出去,还能保证一会儿再切回来
# await 必须写在async函数里,async函数是协程函数
# loop 事件循环
# 所有的协程的执行 调度 都离不开这个loop