1. 协程:

  gevent  (遇到IO自动切换)

  1. import gevent
  2. import time
  3. from gevent import monkey; monkey.patch_all() # ;相当于换行
  4.  
  5. def eat(name):
  6. print('%s eat 1' % name)
  7. # gevent.sleep(1)
  8. time.sleep(2) # gevent 不能识别time.sleep, from gevent import monkey; monkey.patch_all()可解决这个问题, 之后就可以使用time.sleep()了
  9. print('%s eat 2' % name)
  10.  
  11. def play(name):
  12. print('%s play 1' % name)
  13. # gevent.sleep(1)
  14. time.sleep(2)
  15. print('%s play 2' % name)
  16.  
  17. g1 = gevent.spawn(eat, 'alex')
  18. g2 = gevent.spawn(play, name='sylar')
  19. # g1.join()
  20. # g2.join()
  21.  
  22. gevent.joinall([g1, g2])
  23. print('主')

  gevent 之同步与异步

  1. from gevent import spawn,joinall,monkey;monkey.patch_all()
  2.  
  3. import time
  4. def task(pid):
  5. """
  6. Some non-deterministic task
  7. """
  8. time.sleep(0.5)
  9. print('Task %s done' % pid)
  10.  
  11. def synchronous():
  12. for i in range(10):
  13. task(i)
  14.  
  15. def asynchronous():
  16. g_l=[spawn(task,i) for i in range(10)]
  17. joinall(g_l)
  18.  
  19. if __name__ == '__main__':
  20. print('Synchronous:')
  21. synchronous()
  22.  
  23. print('Asynchronous:')
  24. asynchronous()

  gevent 应用列举:

  1. from gevent import monkey;monkey.patch_all()
  2. import gevent
  3. import requests
  4. import time
  5.  
  6. def get_page(url):
  7. print('GET: %s' %url)
  8. response=requests.get(url)
  9. if response.status_code == 200:
  10. print('%d bytes received from %s' %(len(response.text),url))
  11.  
  12. start_time=time.time()
  13. gevent.joinall([
  14. gevent.spawn(get_page,'https://www.python.org/'),
  15. gevent.spawn(get_page,'https://www.yahoo.com/'),
  16. gevent.spawn(get_page,'https://github.com/'),
  17. ])
  18. stop_time=time.time()
  19. print('协程时间>>> %s' %(stop_time-start_time))
  20.  
  21. # 协程应用:爬虫
  22. print('--------------------------------')
  23. s = time.time()
  24. requests.get('https://www.python.org/')
  25. requests.get('https://www.yahoo.com/')
  26. requests.get('https://github.com/')
  27. t = time.time()
  28. print('串行时间>>',t-s)

协程应用: 爬虫

  

参考: https://www.cnblogs.com/clschao/articles/9712056.html#_label4

阻塞 IO

  1. import socket
  2. import time
  3.  
  4. server = socket.socket()
  5. server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  6. server.bind(('127.0.0.1', 8083))
  7. server.listen(5)
  8. print('你看看卡在哪')
  9. while 1:
  10. conn, addr = server.accept() # 等待客户端连接, 阻塞住
  11. print('来自%s的链接请求' % addr)
  12. time.sleep(0.1)

阻塞IO

非阻塞 IO模型

  1. import socket
  2. import time
  3.  
  4. server=socket.socket()
  5. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
  6. server.bind(('127.0.0.1',8083))
  7. server.listen(5)
  8. print('你看看卡在哪')
  9. server.setblocking(False) # 不再阻塞等待
  10. while 1:
  11. try:
  12. conn, addr = server.accept()
  13. print('来自%s的链接请求'%addr)
  14. except BlockingIOError:
  15. print('去买点药')
  16. time.sleep(0.1)
  1. import socket
  2. import time
  3.  
  4. server=socket.socket()
  5. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
  6. server.bind(('127.0.0.1',8083))
  7. server.listen(5)
  8. print('你看看卡在哪')
  9. server.setblocking(False)
  10. rlist = []
  11. rl = []
  12. while 1:
  13. try:
  14. conn, addr = server.accept()
  15. print(addr)
  16. rlist.append(conn)
  17. print('来自%s:%s的链接请求'%(addr[0],addr[1]))
  18. except BlockingIOError:
  19. print('去买点药')
  20.  
  21. time.sleep(0.1) # 防止死循环一直高度占用CPU
  22. print('rlist',rlist,len(rlist))
  23. for con in rlist:
  24. try:
  25. from_client_msg = con.recv(1024)
  26. except BlockingIOError:
  27. continue
  28. except ConnectionResetError:
  29. con.close()
  30. rl.append(con)
  31. print('>>>>',rl)
  32. for remove_con in rl:
  33. rlist.remove(remove_con)
  34. rl.clear()

阻塞IO的socket服务端

  1. import socket
  2. import time
  3.  
  4. ip_port = ('127.0.0.1',8083)
  5.  
  6. client = socket.socket()
  7.  
  8. client.connect(ip_port)
  9.  
  10. while 1:
  11.  
  12. client.send(b'dayangge henweisuo ')
  13. time.sleep(0.1)

阻塞IO的socket客户端

  1. # 服务端
  2. import socket
  3. import time
  4.  
  5. server=socket.socket()
  6. server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
  7. server.bind(('127.0.0.1',8083))
  8. server.listen(5)
  9.  
  10. server.setblocking(False) #设置不阻塞
  11. r_list=[] #用来存储所有来请求server端的conn连接
  12. w_list={} #用来存储所有已经有了请求数据的conn的请求数据
  13.  
  14. while 1:
  15. try:
  16. conn,addr=server.accept() #不阻塞,会报错
  17. r_list.append(conn) #为了将连接保存起来,不然下次循环的时候,上一次的连接就没有了
  18. except BlockingIOError:
  19. # 强调强调强调:!!!非阻塞IO的精髓在于完全没有阻塞!!!
  20. # time.sleep(0.5) # 打开该行注释纯属为了方便查看效果
  21. print('在做其他的事情')
  22. print('rlist: ',len(r_list))
  23. print('wlist: ',len(w_list))
  24.  
  25. # 遍历读列表,依次取出套接字读取内容
  26. del_rlist=[] #用来存储删除的conn连接
  27. for conn in r_list:
  28. try:
  29. data=conn.recv(1024) #不阻塞,会报错
  30. if not data: #当一个客户端暴力关闭的时候,会一直接收b'',别忘了判断一下数据
  31. conn.close()
  32. del_rlist.append(conn)
  33. continue
  34. w_list[conn]=data.upper()
  35. except BlockingIOError: # 没有收成功,则继续检索下一个套接字的接收
  36. continue
  37. except ConnectionResetError: # 当前套接字出异常,则关闭,然后加入删除列表,等待被清除
  38. conn.close()
  39. del_rlist.append(conn)
  40.  
  41. # 遍历写列表,依次取出套接字发送内容
  42. print('wlist: ', len(w_list))
  43. del_wlist=[]
  44. for conn,data in w_list.items():
  45. try:
  46. conn.send(data)
  47. del_wlist.append(conn)
  48. except BlockingIOError:
  49. continue
  50.  
  51. # 清理无用的套接字,无需再监听它们的IO操作
  52. for conn in del_rlist:
  53. r_list.remove(conn)
  54. #del_rlist.clear() #清空列表中保存的已经删除的内容
  55. for conn in del_wlist:
  56. w_list.pop(conn)
  57. #del_wlist.clear()

完整版的非阻塞IO服务端

  1. import socket
  2. import os
  3. import time
  4. import threading
  5. client=socket.socket()
  6. client.connect(('127.0.0.1',8083))
  7.  
  8. while 1:
  9. res=('%s hello' %os.getpid()).encode('utf-8')
  10. client.send(res)
  11. data=client.recv(1024)
  12.  
  13. print(data.decode('utf-8'))
  14.  
  15. ##多线程的客户端请求版本
  16. # def func():
  17. # sk = socket.socket()
  18. # sk.connect(('127.0.0.1',9000))
  19. # sk.send(b'hello')
  20. # time.sleep(1)
  21. # print(sk.recv(1024))
  22. # sk.close()
  23. #
  24. # for i in range(20):
  25. # threading.Thread(target=func).start()

完整版的非阻塞IO客户端

select IO多路复用 (重点)

  1. 当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。  这个图和blockingIO的图其实并没有太大的不同,事实上还更差一些。因为它不仅阻塞了还多需要使用两个系统调用(selectrecvfrom),而blockingIO只调用了一个系统调用(recvfrom),当只有一个连接请求的时候,这个模型还不如阻塞IO效率高。但是,用select的优势在于它可以同时处理多个connection,而阻塞IO那里不能,我不管阻塞不阻塞,你所有的连接包括recv等操作,我都帮你监听着(以什么形式监听的呢?先不要考虑,下面会讲的~~),其中任何一个有变动(有链接,有数据),我就告诉你用户,那么你就可以去调用这个数据了,这就是他的NB之处。这个IO多路复用模型机制是操作系统帮我们提供的,在windows上有这么个机制叫做select,那么如果我们想通过自己写代码来控制这个机制或者自己写这么个机制,我们可以使用python中的select模块来完成上面这一系列代理的行为。在一切皆文件的unix下,这些可以接收数据的对象或者连接,都叫做文件描述符fd

IO多路复用

  1. import select
  2.  
  3. fd_r_list, fd_w_list, fd_e_list = select.select(rlist, wlist, xlist, [timeout])
  4.  
  5. 参数: 可接受四个参数(前三个必须)
  6. rlist: wait until ready for reading #等待读的对象,你需要监听的需要获取数据的对象列表
  7. wlist: wait until ready for writing #等待写的对象,你需要写一些内容的时候,input等等,也就是说我会循环他看看是否有需要发送的消息,如果有我取出这个对象的消息并发送出去,一般用不到,这里我们也给一个[]。
  8. xlist: wait for an exceptional condition #等待异常的对象,一些额外的情况,一般用不到,但是必须传,那么我们就给他一个[]。
  9. timeout: 超时时间
  10. 当超时时间 n(正整数)时,那么如果监听的句柄均无任何变化,则select会阻塞n秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。
  11. 返回值:三个列表与上面的三个参数列表是对应的
  12.   select方法用来监视文件描述符(当文件描述符条件不满足时,select会阻塞),当某个文件描述符状态改变后,会返回三个列表
  13. 1、当参数1 序列中的fd满足“可读”条件时,则获取发生变化的fd并添加到fd_r_list
  14. 2、当参数2 序列中含有fd时,则将该序列中所有的fd添加到 fd_w_list
  15. 3、当参数3 序列中的fd发生错误时,则将该发生错误的fd添加到 fd_e_list
  16. 4、当超时时间为空,则select会一直阻塞,直到监听的句柄发生变化

介绍

  1. #服务端
  2. from socket import *
  3. import select
  4. server = socket(AF_INET, SOCK_STREAM)
  5. server.bind(('127.0.0.1',8093))
  6. server.listen(5)
  7. # 设置为非阻塞
  8. server.setblocking(False)
  9.  
  10. # 初始化将服务端socket对象加入监听列表,后面还要动态添加一些conn连接对象,当accept的时候sk就有感应,当recv的时候conn就有动静
  11. rlist=[server,]
  12. rdata = {} #存放客户端发送过来的消息
  13.  
  14. wlist=[] #等待写对象
  15. wdata={} #存放要返回给客户端的消息
  16.  
  17. print('预备!监听!!!')
  18. count = 0 #写着计数用的,为了看实验效果用的,没用
  19. while True:
  20. # 开始 select 监听,对rlist中的服务端server进行监听,select函数阻塞进程,直到rlist中的套接字被触发(在此例中,套接字接收到客户端发来的握手信号,从而变得可读,满足select函数的“可读”条件),被触发的(有动静的)套接字(服务器套接字)返回给了rl这个返回值里面;
  21. rl,wl,xl=select.select(rlist,wlist,[],0.5)
  22. print('%s 次数>>'%(count),wl)
  23. count = count + 1
  24. # 对rl进行循环判断是否有客户端连接进来,当有客户端连接进来时select将触发
  25. for sock in rl:
  26. # 判断当前触发的是不是socket对象, 当触发的对象是socket对象时,说明有新客户端accept连接进来了
  27. if sock == server:
  28. # 接收客户端的连接, 获取客户端对象和客户端地址信息
  29. conn,addr=sock.accept()
  30. #把新的客户端连接加入到监听列表中,当客户端的连接有接收消息的时候,select将被触发,会知道这个连接有动静,有消息,那么返回给rl这个返回值列表里面。
  31. rlist.append(conn)
  32. else:
  33. # 由于客户端连接进来时socket接收客户端连接请求,将客户端连接加入到了监听列表中(rlist),客户端发送消息的时候这个连接将触发
  34. # 所以判断是否是客户端连接对象触发
  35. try:
  36. data=sock.recv(1024)
  37. #没有数据的时候,我们将这个连接关闭掉,并从监听列表中移除
  38. if not data:
  39. sock.close()
  40. rlist.remove(sock)
  41. continue
  42. print("received {0} from client {1}".format(data.decode(), sock))
  43. #将接受到的客户端的消息保存下来
  44. rdata[sock] = data.decode()
  45.  
  46. #将客户端连接对象和这个对象接收到的消息加工成返回消息,并添加到wdata这个字典里面
  47. wdata[sock]=data.upper()
  48. #需要给这个客户端回复消息的时候,我们将这个连接添加到wlist写监听列表中
  49. wlist.append(sock)
  50. #如果这个连接出错了,客户端暴力断开了(注意,我还没有接收他的消息,或者接收他的消息的过程中出错了)
  51. except Exception:
  52. #关闭这个连接
  53. sock.close()
  54. #在监听列表中将他移除,因为不管什么原因,它毕竟是断开了,没必要再监听它了
  55. rlist.remove(sock)
  56. # 如果现在没有客户端请求连接,也没有客户端发送消息时,开始对发送消息列表进行处理,是否需要发送消息
  57. for sock in wl:
  58. sock.send(wdata[sock])
  59. wlist.remove(sock)
  60. wdata.pop(sock)
  61.  
  62. # #将一次select监听列表中有接收数据的conn对象所接收到的消息打印一下
  63. # for k,v in rdata.items():
  64. # print(k,'发来的消息是:',v)
  65. # #清空接收到的消息
  66. # rdata.clear()
  67.  
  68. ---------------------------------------
  69. #客户端
  70. from socket import *
  71.  
  72. client=socket(AF_INET,SOCK_STREAM)
  73. client.connect(('127.0.0.1',8093))
  74.  
  75. while True:
  76. msg=input('>>: ').strip()
  77. if not msg:continue
  78. client.send(msg.encode('utf-8'))
  79. data=client.recv(1024)
  80. print(data.decode('utf-8'))
  81.  
  82. client.close()
  83.  
  84. select网络IO模型的示例代码

select网络IO模型示例代码

select IO多路复用 异步

异步IO  asyncio (很厉害, 高并发)

Day038--Python--Gevent , IO多路复用的更多相关文章

  1. {python之IO多路复用} IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO(Asynchronous I/O) IO模型比较分析 selectors模块

    python之IO多路复用 阅读目录 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 ...

  2. day36 python学习gevent io 多路复用 socketserver *****

    ---恢复内容开始--- gevent 1.切换+保存状态 2.检测单线程下任务的IO,实现遇到IO自动切换 Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在geven ...

  3. python中IO多路复用、协程

    一.IO多路复用 IO多路复用:检测多个socket是否已经发生变化(是否已经连接成功/是否已经获取数据)(可读/可写) import socket def get_data(key): client ...

  4. python之IO多路复用

    在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...

  5. 【python】-- IO多路复用(select、poll、epoll)介绍及实现

    IO多路复用(select.poll.epoll)介绍及select.epoll的实现 IO多路复用中包括 select.pool.epoll,这些都属于同步,还不属于异步 一.IO多路复用介绍 1. ...

  6. 09 Python之IO多路复用

    四种常见IO模型 阻塞IO(blocking IO).非阻塞IO(nonblocking IO).IO多路复用(IOmultiplexing).异步IO(asynchronous IO) IO发生时涉 ...

  7. Python poll IO多路复用

    一.poll介绍 poll本质上和select没有区别,只是没有了最大连接数(linux上默认1024个)的限制,原因是它基于链表存储的. 本人的另一篇博客讲了 python  select : ht ...

  8. Python select IO多路复用

    一.select介绍 Python的select()函数是底层操作系统实现的直接接口.它监视套接字,打开文件和管道(任何带有返回有效文件描述符的fileno()方法),直到它们变得可读或可写,或者发生 ...

  9. Python之路,Day9 - 线程、进程、协程和IO多路复用

    参考博客: 线程.进程.协程: http://www.cnblogs.com/wupeiqi/articles/5040827.html http://www.cnblogs.com/alex3714 ...

  10. Python进程、线程、协程及IO多路复用

    详情戳击下方链接 Python之进程.线程.协程 python之IO多路复用

随机推荐

  1. ORA-12537: Network Session: End of file

    最近开发组同事使用Azure的Function App访问公司内部的Oracle数据库时,偶尔会遇到"ORA-12537: Network Session: End of file" ...

  2. python2.7生成exe可执行文件

    1.安装对应python版本的py2exe py2exe下载地址 2.假设你要生成test.py脚本的exe文件 新建一个setup.py,在里面输入如下代码 #!/usr/bin/python fr ...

  3. 三机互ping(自己总结)

    主机与虚拟机互ping设置: 点击VMware下的[编辑]--[虚拟网络编辑器]设置如下:         屏幕剪辑的捕获时间: 2016/5/21 13:10         屏幕剪辑的捕获时间: ...

  4. LeetCode算法题-Valid Palindrome II(Java实现)

    这是悦乐书的第287次更新,第304篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第155题(顺位题号是680).给定非空字符串s,最多可以删除一个字符. 判断它是否是回 ...

  5. LeetCode算法题-Non-decreasing Array(Java实现)

    这是悦乐书的第283次更新,第300篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第151题(顺位题号是665).给定一个包含n个整数的数组,您的任务是通过修改最多1个元 ...

  6. Spring Boot 知识图谱

    最近有意重新学习下SpringBoot知识,特地总结了SpringBoot的知识点,对于想要学习的人来说,够用. SpringBoot学习路径 第一部分:了解 Spring Boot Spring B ...

  7. centos7下kubernetes(13。kubernetes-探讨service IP)

    service cluster IP是一个虚拟IP,是由kubernetes节点上的iptables规则管理的 通过iptables-save | grep 10.105.215.156看到与clus ...

  8. R语言学习——数据框

    > #数据框可以包含不同模式(数值型.字符型.逻辑型等)的数据,是R中最常处理的数据结构.数据框可以通过函数data.frame()创建:mydata<-data.frame(coll,c ...

  9. python3 pickle模块

    import pickle '''将对象转化为硬盘能识别的bytes的过程被称为序列号将bytes转化为对象的过程被称为反序列化'''lst = ["苹果", "橘子&q ...

  10. [看图说话]在VMware Workstation 9中安装Mac OS X 10.8 Mountain Lion

    本文环境: CPU:Intel Core i7 920: OS:Windows 7: 内存:8G: 玩Hackintosh各有各的理由,不管什么理由,利用虚拟机安装Mac OS X都是一个可行的办法. ...