您的位置:首页 > 编程语言

并发编程---协程

2020-02-01 00:59 906 查看

协程

协程: 单线程下的并发,应用程序控制的并发,是用户自己调度的,自己控制自己的速度快。

协程:单线程下的并发,并不是对性能都有所提升,而是监测单线程下的IO行为,遇到IO行为不让原地阻塞,切换到另一个任务执行。

 

并发: 切换任务+保存状态

单线程下实现并发:单线程下的多个任务,遇到IO就切,把单线程整体的IO降到最低。相当于把自己的IO伪装起来,让操作系统将更多的CPU分配给线程。程序用的cpu多,就叫执行效率高

总结协程特点:

  • 必须在只有一个单线程里实现并发
  • 修改共享数据不需加锁
  • 用户程序里自己保存多个控制流的上下文栈
  • 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))
协程

greenlet模块

  • 再多个任务可以很方便的切,但不能检测到,遇到IO 切
  • 比yield 好,但是还是不好,遇到io不会切
from greenlet import greenlet
import time

def eat(name):
print('%s eat1' %name)
# time.sleep(10) 遇到IO不会切
g2.switch('yang')
print('%s eat2' %name)
g2.switch()

def play(name):
print('%s play1' %name)
g1.switch()
print('%s play2' %name)

g1 = greenlet(eat)
g2 = greenlet(play)

g1.switch('yang') #第一次启动需要传参数
'''
打印结果:
yang eat1
yang play1
yang eat2
yang play2
'''
greenlet模块

gevent模块

gevent: 里面封装了greenlet模块,但是可以检测到IO操作,自动切换任务

缺点:只能检测到gevent.sleep()等,gevent的IO阻塞

解决方法:导入gevent模块下的monkey方法,在文件的开头写:from gevent import monkey;monkey.patch_all()

from gevent import monkey;monkey.patch_all()
import gevent
import time

def eat(name):
print('%s eat1' %name)
gevent.sleep(3)
print('%s eat2' %name)

def play(name):
print('%s play1' %name)
gevent.sleep(4)
print('%s play2' %name)

start_time = time.time()
g1 = gevent.spawn(eat,'yang')
g2 = gevent.spawn(play,'hang')

g1.join()
g2.join()
stop_time = time.time()
print(stop_time-start_time)
'''
打印结果:
yang eat1
hang play1
yang eat2
hang play2
4.004916191101074
gevent换成time的话:
执行时间就变成7秒多
'''

from gevent import monkey;monkey.patch_all()
import gevent
import time

def eat(name):
print('%s eat1' %name)
gevent.sleep(3)
print('%s eat2' %name)

def play(name):
print('%s play1' %name)
gevent.sleep(4)
print('%s play2' %name)

g1 = gevent.spawn(eat,'yang')
g2 = gevent.spawn(play,'hang')

# g1.join() # 等到g1执行完
# g2.join() # 等到g2执行完

gevent.joinall([g1,g2 ]) # 等到g1和g2都执行完
g1.join()
g2.join()

"""
打印结果:
egon eat 1
alex play 1
egon eat 2
alex play 2
"""
gevent模块

gevent模块下的套接字通信

#基于gevent实现
import socket
from gevent import monkey,spawn;monkey.patch_all()

def communicate(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):
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((ip,port))
server.listen(5)

while True:
conn, addr = server.accept()
spawn(communicate,conn)

server.close()

if __name__ == '__main__':
g = spawn(server,'127.0.0.1',8090)
g.join()
服务端
import socket
from threading import Thread,currentThread

def client():
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8090))

while True:
client.send(('%s hello' %currentThread().getName()).encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
client.close()

if __name__ == '__main__':
for i in range(500): # 500个客户端同时登陆,服务端一个线程就可以接收500个client
t = Thread(target=client)
t.start()
# 单线程的IO降下来,会大大提高程序的效率
客户端

转载于:https://www.cnblogs.com/Mryang123/p/8928987.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
bailun4507 发布了0 篇原创文章 · 获赞 0 · 访问量 130 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: