引子:

之前学习过了,线程,进程的概念,知道了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位.按道理来说我们已经算是把CPU的利用率提高很多了.但是我们知道无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程,创建线程,以及管理他们之间的切换.

随着我们对于效率的最求不断提高,基于单线程来实现并发又成为一个新的课题.即只用一个主线程的情况下实现并发.这样就可以节省创建线程进程所消耗的时间.

并发的本质: 切换+保存状态

cpu正在运行一个任务,会在两种情况下切走去执行其他的任务(切换由操作系统强制控制),一种情况是任务发生了阻塞,另外一种情况是该任务计算时间过长

对于单线程下,我们不可避免程序中出现io操作,但如果我们能在自己的程序中(即用户程序级别,而非操作系统级别)控制单线程下的多个任务能在一个任务遇到io阻塞时就切换到另外一个任务去计算,这样就保证了该线程能够最大限度地处于就绪态,即随时都可以被cpu执行的状态,相当于我们在用户程序级别将自己的io操作最大限度地隐藏起来,从而可以迷惑操作系统,让其看到:该线程好像是一直在计算,io比较少,从而更多的将cpu的执行权限分配给我们的线程。

协成的本质就是在单线程下,由用户自己控制一个任务遇到IO阻塞就切换另一个任务去执行,一次来提升效率.

#可以控制对个任务之间的切换,切换之前将任务的状态保存下来,以便重新运行时,可以基于暂停的位置继续执行.#作为1的补充;可以检测IO操作,在遇到IO操作的情况下才发生切换

协程介绍:

协程:是单线程下的并发,又称为为线程. 协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的.

协程特点:

必须在只有一个单线程里实现并发

修改共享数据不需加锁

用户程序里自己保存多个控制流的上下文栈

一个协程遇到IO操作自动切换到其他协程

Greenlet模块

安装:pip3 install greenlet

from greenlet importgreenletdefeat(name):print('%s eat 1'%name)

g2.switch('egon')print('%s eat 2'%name)

g2.switch()defplay(name):print('%s play 1' %name)

g1.switchprint('%s play 2' %name)

g1=greenlet(eat)

g2=greenlet(play)

g1.switch('egon')#可以在第一次switch时传入参数,以后都不需要

greenlet实现状态切换

Gevent模块

安装:pip3 install gevent

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet,它是以C扩展模块形式接入Python的轻量级线程.Greenlet全部运行在主程序操作系统进程的内部,但他们被协作式的调度.

importgeventdefeat(name):print('%s eat 1' %name)

gevent.sleep(2)print('%s eat 2' %name)defplay(name):print('%s play 1' %name)

gevent.sleep(1)print('%s play 2' %name)

g1=gevent.spawn(eat,'egon')

g2=gevent.spawn(play,name='egon')

g1.join()

g2.join()#或者gevent.joinall([g1,g2])

print('主')

遇到IO主动切换

IO多路复用

IO多路复用作用:检查多个socket是否已经发生变化(是否连接成功/是否已经获取数据)(可读/可写)

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。

三种模式:

select:最多1024个socket;循环去检测。

poll:不限制监听socket个数;循环去检测(水平触发)。

epoll:不限制监听socket个数;回调方式(边缘触发)。

基于IO多路复用+socket实现并发请求:

IO多路复用

socket 非阻塞(不等待)

异步:执行完某个任务后自动调用我给它的函数

Python中开源  基于事件循环实现的异步非阻塞框架  Twisted

importsocketimportrequests#方式一

ret = requests.get('https://www.baidu.com/s?wd=alex')#方式二

client =socket.socket()#百度创建连接: 阻塞

client.connect(('www.baidu.com',80))#问百度我要什么?

client.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')#我等着接收百度给我的回复

chunk_list =[]whileTrue:

chunk= client.recv(8096)if notchunk:breakchunk_list.append(chunk)

body= b''.join(chunk_list)print(body.decode('utf-8'))

socket发生请求

importsocketimportrequests#方式一

key_list = ['alex','db','sb']for item inkey_list:

ret= requests.get('https://www.baidu.com/s?wd=%s' %item)#方式二

defget_data(key):#方式二

client =socket.socket()#百度创建连接: 阻塞

client.connect(('www.baidu.com',80))#问百度我要什么?

client.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')#我等着接收百度给我的回复

chunk_list =[]whileTrue:

chunk= client.recv(8096)if notchunk:breakchunk_list.append(chunk)

body= b''.join(chunk_list)print(body.decode('utf-8'))

key_list= ['alex','db','sb']for item inkey_list:

get_data(item)

单线程解决并发

importthreading

key_list= ['alex','db','sb']for item inkey_list:

t= threading.Thread(target=get_data,args=(item,))

t.start()

解决并发,多线程

提高并发方案:

--多进程

--多线程

--异步非阻塞模块(Twisted)  scrapy框架(单线程完成并发)

importsocketimportselect

client1=socket.socket()

client1.setblocking(False)#百度创建连接: 非阻塞

try:

client1.connect(('www.baidu.com',80))exceptBlockingIOError as e:passclient2=socket.socket()

client2.setblocking(False)#百度创建连接: 非阻塞

try:

client2.connect(('www.sogou.com',80))exceptBlockingIOError as e:passclient3=socket.socket()

client3.setblocking(False)#百度创建连接: 非阻塞

try:

client3.connect(('www.oldboyedu.com',80))exceptBlockingIOError as e:passsocket_list=[client1,client2,client3]

conn_list=[client1,client2,client3]whileTrue:

rlist,wlist,elist= select.select(socket_list,conn_list,[],0.005)#wlist中表示已经连接成功的socket对象

for sk inwlist:if sk ==client1:

sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')elif sk==client2:

sk.sendall(b'GET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n')else:

sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.oldboyedu.com\r\n\r\n')

conn_list.remove(sk)for sk inrlist:

chunk_list=[]whileTrue:try:

chunk= sk.recv(8096)if notchunk:breakchunk_list.append(chunk)exceptBlockingIOError as e:breakbody= b''.join(chunk_list)#print(body.decode('utf-8'))

print('------------>',body)

sk.close()

socket_list.remove(sk)if notsocket_list:break

单线程完成并发

什么是异步非阻塞?

--非阻塞:不等待

比如创建socket对某个地址进行connect,获取接收数据recv时默认都会等待(连接成功或接收到数据),才执行后续操作.如果设置setblocking(False),以上两个过程就不在等待,到时会报BlockingIOError的错误,只要捕获即可.

--异步,通知,执行完成后自动执行回调函数或自动执行某些操作(通知)

比如做爬虫中向某个地址baidu.com发送请求,当请求执行完成之后自动执行回调函数.

什么是同步阻塞?

--阻塞:等

--同步:按照顺序逐步执行

key_list = ['alex','db','sb']for item inkey_list:

ret= requests.get('https://www.baidu.com/s?wd=%s' %item)print(ret.text)

python io多路复用_Python之路--协程/IO多路复用相关推荐

  1. Python之路--协程/IO多路复用

    引子: 之前学习过了,线程,进程的概念,知道了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位.按道理来说我们已经算是把CPU的利用率提高很多了.但是我们知道无论是创建多进程还是创建多 ...

  2. python异步爬虫_Python实现基于协程的异步爬虫

    Python实现基于协程的异步爬虫 一.课程介绍 1. 课程来源 本课程核心部分来自<500 lines or less>项目,作者是来自 MongoDB 的工程师 A. Jesse Ji ...

  3. GO语言的进阶之路-协程和Channel

    GO语言的进阶之路-协程和Channel 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 看过我之前几篇博客小伙伴可能对Golang语言的语法上了解的差不多了,但是,如果想要你的代码 ...

  4. python网络编程库_Python网络编程——协程

    协程的概念 协程,又称微线程,纤程,也称用户级线程,在不开辟线程的基础上实现多任务,也就是在单线程的情况下完成多任务,多个任务按照一定顺序交替执行的,通俗理解只要在def里面只看到一个yield关键字 ...

  5. Python之路--Python基础12--并发编程之协程

    一.协程介绍 1.引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态.cpu正在运行一个任务,会在两 ...

  6. python从网址爬图片协程_python 用 gevent 协程抓取海量网页

    python作为爬虫利器,抓网页的方式简洁明了.爬成百上千的网页,都可以很快爬完,但是如果网页数量上万呢?速度就不能忍受了. 这是一段爬取页面的函数,用了requests库:1 2 3 4 5impo ...

  7. python协程实现一万并发_python中的协程并发

    python asyncio 网络模型有很多中,为了实现高并发也有很多方案,多线程,多进程.无论多线程和多进程,IO的调度更多取决于系统,而协程的方式,调度来自用户,用户可以在函数中yield一个状态 ...

  8. python 协程是啥_python中的协程

    协程,又称微线程,纤程.英文名Coroutine. 协程是啥 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源). 为啥说它是一个执行单元,因为它自带 ...

  9. python 协程可以嵌套协程吗_Python线程、协程探究(2)——揭开协程的神秘面纱...

    一.上集回顾 在上一篇中我们主要研究了python的多线程困境,发现多核情况下由于GIL的存在,python的多线程程序无法发挥多线程该有的并行威力.在文章的结尾,我们提出如下需求: 既然python ...

  10. python从网址爬图片协程_Python爬虫多任务协程爬取虎牙MM图片

    查看: 4420|回复: 241 [作品展示] Python爬虫多任务协程爬取虎牙MM图片 电梯直达 发表于 2019-4-17 21:35:47 | 只看该作者 |倒序浏览 |阅读模式 马上注册,结 ...

最新文章

  1. Win10 新版又悲剧了!老外神评论
  2. Ruby的.nil? .empty? .blank? .present?区别
  3. windows下配置mysql主从复制_Windows下MySQL主从复制的配置方法
  4. iscroll的使用
  5. 2021上半年短视频及电商生态研究报告
  6. 最新SSM完整模板(Spring+SpringMVC+MybatisPlus)
  7. gitlab版本控制系统源码部署
  8. vue打开二级或者三级页面传输对象,再刷新浏览器数据丢失问题解决(vue使用router传递数据)
  9. 10. 在constructors内阻止资源泄露
  10. monkey_使用_脚本编写
  11. 区块链 Fisco bcos 智能合约(11)-深入浅出Solidity
  12. 计算机电路板工作原理,充电宝电路板原理图的说明
  13. 记录贴:阿里云 ECS服务器CentOS系统 搭建 Hexo 博客详细教程
  14. 荣耀 android 5.0 root,华为EMUI5.0 可用的ROOT工具,我是作者!!!!——精华帖
  15. 在企业中采用知识管理工具的好处
  16. 网易软件测试面试总结分享——送给正在找工作的你
  17. 顶级在线图片处理工具Photopea
  18. 计算机word打开,电脑word打不开怎么办
  19. js 获取浏览器屏幕的宽度和高度
  20. PR标题动画模板 创意动态多行标题注释字幕条pr模板

热门文章

  1. 华为机试:提取不重复的整数
  2. 【数据库开发】MySQL修改root密码
  3. java控制台输入输出
  4. SOJ 4482 忽悠大神【最小生成树】
  5. linux 内核源码牛人分析 链接分享
  6. VS快速定位文件、代码插件——DPack
  7. CBMVC For Titanium Alloy 发布!
  8. linux Shell学习笔记第二天
  9. AWK相关学习(转)
  10. 将CString转换成string ...