9.14 线程Event
connect线程执行到event.wait()时开始等待,直到check线程执行event.set()后立即继续线程connect
from threading import Event,current_thread,Thread
import time
event=Event()
def check():
print('%s 正在检测服务是否正常....' %current_thread().name)
time.sleep(3)
event.set()
def connect():
print('%s 等待连接...' %current_thread().name)
event.wait()
print('%s 开始连接...' % current_thread().name)
if __name__ == '__main__':
t1=Thread(target=connect)
t2=Thread(target=connect)
t3=Thread(target=connect)
c1=Thread(target=check)
t1.start()
t2.start()
t3.start()
c1.start()
connect线程执行到event.wait(1)时开始等待1秒,count计数+1,如果到check线程执行event.set()前已经4秒,则终止线程connect,否则event.is_set() is True ,立即继续线程connect
from threading import Event,current_thread,Thread
import time
event=Event()
def check():
print('%s 正在检测服务是否正常....' %current_thread().name)
time.sleep(5)
event.set()
def connect():
count=1
while not event.is_set(): #event是否被set过,是返回True,否返回False
if count == 4:
print('尝试的次数过多,请稍后重试')
return
print('%s 尝试第%s次连接...' %(current_thread().name,count))
event.wait(1)
count+=1
print('%s 开始连接...' % current_thread().name)
if __name__ == '__main__':
t1=Thread(target=connect)
t2=Thread(target=connect)
t3=Thread(target=connect)
c1=Thread(target=check)
t1.start()
t2.start()
t3.start()
c1.start()
9.15 协程
协程:是单线程下的并发,又称微线程,纤程。一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到i/o或执行时间过长就会*交出cpu执行权限,切换其他线程运行)
单线程内开启协程,一旦遇到i/o,就会从应用程序级别(而非操作系统)控制切换到其他任务,以此来提升效率(非i/o操作的切换与效率无关)
对比操作系统控制线程的切换,用户在单线程内控制协程的切换
优点:
1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
2. 单线程内就可以实现并发的效果,最大限度地利用cpu
缺点:
1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
9.151 greenlet模块
from greenlet import greenlet
import time def eat(name):
print('%s eat 1' %name)
#time.sleep(30) 遇到i/o不能自动切换
g2.switch('alex')
print('%s eat 2' %name)
g2.switch()
def play(name):
print('%s play 1' %name)
g1.switch()
print('%s play 2' %name) g1=greenlet(eat)
g2=greenlet(play) g1.switch('egon') # egon eat 1 alex play 1 egon eat 2 alex play 2
9.152 gevent模块
import gevent
def eat(name):
print('%s eat 1' %name)
gevent.sleep(5) #只检测gevent的i/o
print('%s eat 2' %name)
def play(name):
print('%s play 1' %name)
gevent.sleep(3)
print('%s play 2' %name)
g1=gevent.spawn(eat,'egon') #异步提交任务
g2=gevent.spawn(play,'alex')
# gevent.sleep(100)
# g1.join()
# g2.join() # joinall等待任务执行完毕再结束线程
gevent.joinall([g1,g2]) # egon eat 1 alex play 1 alex play 2 egon eat 2
from gevent import monkey;monkey.patch_all()#标记所有(包括time等)的i/o
import gevent
import time
def eat(name):
print('%s eat 1' %name)
time.sleep(5) #time的i/o也可以检测
print('%s eat 2' %name)
def play(name):
print('%s play 1' %name)
time.sleep(3)
print('%s play 2' %name)
g1=gevent.spawn(eat,'egon')
g2=gevent.spawn(play,'alex')
# gevent.sleep(100)
# g1.join()
# g2.join()
gevent.joinall([g1,g2]) # egon eat 1 alex play 1 alex play 2 egon eat 2
验证协程的假名:
from gevent import monkey;monkey.patch_all()#标记所有time等的i/o
from threading import current_thread
import gevent
import time
def eat():
print('%s eat 1' %current_thread().name)
time.sleep(5)
print('%s eat 2' %current_thread().name)
def play():
print('%s play 1' %current_thread().name)
time.sleep(3)
print('%s play 2' %current_thread().name)
g1=gevent.spawn(eat)
g2=gevent.spawn(play)
# gevent.sleep(100)
# g1.join()
# g2.join()
print(current_thread().name)#MainThread
gevent.joinall([g1,g2]) #DummyThread-1 eat 1 DummyThread-2 play 1 DummyThread-2 play 2 DummyThread-1 eat 2
9.153 基于协程实现并发的套接字通信
服务端:
from gevent import monkey,spawn;monkey.patch_all()#标记所有time等的i/o
from threading import Thread
from socket import *
def talk(conn):
while True:
try:
data=conn.recv(1024)
if not data:break
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()
def server(ip,port,backlog=5):
s = socket()
s.bind((ip,port))
s.listen(backlog)
while True:
conn, addr = s.accept()
print(addr) g=spawn(talk,conn) # 通信
s.close()
if __name__ == '__main__':
spawn(server,'127.0.0.1',8080).join()
# server(('127.0.0.1',8080))
客户端:
from threading import Thread,current_thread
from socket import *
import os
def client():
client = socket()
client.connect(('127.0.0.1', 8080))
while True:
data = '%s hello' % current_thread().name
client.send(data.encode('utf-8'))
res = client.recv(1024)
print(res.decode('utf-8'))
if __name__ == '__main__':
for i in range(1000):
t=Thread(target=client)
t.start()