并发、并行,同步、异步,阻塞、非阻塞

并发、并行
  • 并发是在一个时间段内,有几个程序在同一个cpu上运行,但是任意时刻只有一个程序在cpu上运行。
  • 并行是任意时刻点上,有多个程序同时运行在多个cpu上。
同步、异步
  • 同步是指代码调用IO操作时,必须等待IO操作完成才返回的调用方式。
  • 异步是指代码调用IO操作时,不必等待IO操作完成就返回的调用方式。
阻塞、非阻塞
  • 阻塞是指调用函数时候当前线程被挂起。
  • 非阻塞是指调用函数时候当前线程不会被挂起,而是立即返回。

阻塞和非阻塞的概念和同步异步感觉很像,但是其实它们之间是有区别的。

区别:

同步和异步实际上是消息通信的一种机制,可以把IO操作看做一个消息,调用IO操作时,相当于发一个消息给另外一个线程(或者说另外一个协程),让它去执行某些操作,在提交数据之后立刻得到future,后边就可以通过future拿到结果,实际上是消息之间的通信机制。

阻塞和非阻塞是不同于同步异步的,它是函数调的一种机制。

IO 多路复用 (select、poll 和 epoll)

unix中五种I/O模型

  1. 阻塞式I/O
  2. 非阻塞式I/O
  3. I/O复用
  4. 信号驱动式I/O (用的比较少)
  5. 异步I/O (POSIX的aio_系列函数)

以上五种是递进式的发展。

I/O多路复用:

select方法也是阻塞的方法,select本身是阻塞式的,select可以监听多个文件句柄和socket,select在某一个文件句柄或者socket准备好的话就会返回,这时候立刻可以做业务逻辑处理。

I/O多路复用带来的好处是:

比如现在同时发起了100个非阻塞式的请求,这时候直接使用select去监听这100个socket,这样的话一旦有一个发生状态变化,我们就可以立马处理它。

I/O多路复用中,将数据从内核复制到用户空间这段时间消耗还是省不了。

异步IO:

这里的异步IO是真正意义上的异步IO(aio),我们现在接触到很多高并发框架实际上都没有使用异步IO,实际上在很大程度上使用的都是io多路复用技术,IO多路复用很成熟很稳定,异步IO对于IO多路复用性能提升并没有达到很明显的程度,但是编码难度有很大提升,所以当前情况下IO多路复用用的比较多。
异步IO节省掉了数据从内核拷贝到用户空间这一步骤。

select、poll、epoll:

select、poll、epoll都是I/O多路复用的机制。
I/O多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般就是读就绪或写就绪),能够通知程序进行相应的读写操作。
但select、poll、epoll本质上都是同步I/O,因为它们都需要在读写事件就绪后自己负责进行读写(数据从内核拷贝到用户区),也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。

select是什么?

select 函数监视的文件描述符分三类,分别是writefds、readfds、exceptfds。调用select后会阻塞,直到有描述符就绪(有数据可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以通过遍历fdset来找到就绪的描述符。
select目前几乎在所有的平台上支持,其良好的跨平台也是它的一个优点。select的一个缺点在于单个进程监视的文件描述符的数量有最大限制,在linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一性质,但是这样也会造成效率的降低。

poll是什么?

不同于select使用三个位图来表示三个fdset的方式,poll使用一个pollfd的指针实现。pollfd结构包含了要监视的event和发生的event,不再使用select "参数-值" 传递的方式。同时,pollfd并没有最大数量限制(但是数量过大性能也会下降)。和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。

从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪的状态,因此随着监视的描述符数量的增长,其效率也会线性下降。

epoll是什么?

epoll是在2.6内核中提出的,epoll是之前的select和poll的增强版本。相对于select和poll来讲,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需要一次。
epoll它的查询使用了数据结构中性能很高的一个:红黑树。
nginx就是使用了epoll。

epoll并不代表一定比select好:

  • 在并发高的情况下,连接活跃度不是很高, epoll比select。
  • 并发性不高,同时连接很活跃, select比epoll好。

非阻塞I/O实现http请求

上示例代码:

import socket
from urllib.parse import urlparse
def get_url(url):# 通过socket请求htmlurl = urlparse(url)host = url.netlocpath = url.pathif path == "":path = "/"# 建立socket连接client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 这里会导致后边抛异常,但是连接请求已经发出去了client.setblocking(False)# 捕获异常try:client.connect((host, 80)) # 阻塞不会消耗cpuexcept BlockingIOError as e:pass# 不停的询问连接是否建立好, 需要while循环不停的去检查状态# 做计算任务或者再次发起其他的连接请求while True:try:client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(path, host).encode("utf8"))breakexcept OSError as e:passdata = b""while True:# 这里还会抛异常,读不到就继续读try:d = client.recv(1024)except BlockingIOError as e:continueif d:data += delse:breakdata = data.decode("utf8")html_data = data.split("\r\n\r\n")[1]#打印返回的数据print(html_data)client.close()if __name__ == "__main__":get_url("http://www.baidu.com")

非阻塞I/O整个过程依赖前后的监测,整个过程不停的做while循环检测状态,但是返回时间没有变,所以并没有提高并发。

select+回调+事件循环实现http请求

目前开源的高性能框架,一般都是使用这种方式实现并发。
使用select + 回调 + 事件循环实现下载网页,并发性高且是单线程。

select方法本尊是在import select这个包里边,但是有另外一个包把select基础上进行了封装,用起来更简单:from selectors import DefaultSelector,DefaultSelector一般使用DefaultSelector这个比较多。

看代码示例:

import socket
import time
from urllib.parse import urlparse
from selectors import DefaultSelector, EVENT_READ, EVENT_WRITEselector = DefaultSelector()
urls = []
stop = Falseclass Fetcher:def connected(self, key):selector.unregister(key.fd)self.client.send("GET {} HTTP/1.1\r\nHost:{}\r\nConnection:close\r\n\r\n".format(self.path, self.host).encode("utf8")selector.register(self.client.fileno(), EVENT_READ, self.readable)# 当socket可读时,读数据,全部都是cpu操作def readable(self, key):d = self.client.recv(1024)if d:self.data += delse:# 数据读完为空selector.unregister(key.fd)data = self.data.decode("utf8")html_data = data.split("\r\n\r\n")[1]print(html_data[:30])self.client.close()urls.remove(self.spider_url)if not urls:global stopstop = Truedef get_url(self, url):self.spider_url = urlurl = urlparse(url)self.host = url.netlocself.path = url.pathself.data = b""if self.path == "":self.path = "/"# 建立 socket 连接self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.client.setblocking(False)try:self.client.connect((self.host, 80))  # 阻塞不会消耗cpuexcept BlockingIOError as e:passselector.register(self.client.fileno(), EVENT_WRITE, self.connected)# 驱动整个事件循环
def loop():while not stop:ready = selector.select()for key, mask in ready:call_back = key.datacall_back(key)if __name__ == "__main__":# 计时开始start_time = time.time()for url in range(60):url = "http://www.baidu.com"urls.append(url)fetcher = Fetcher()fetcher.get_url(url)loop()print(time.time()-start_time)

上边代码中,Fetcher类包含三个方法,get_url简历socket连接,connected和readable是两个回调函数。
loop函数负责驱动整个事件循环。

回调的缺点

  1. 可读性差
  2. 共享状态异常处理
  3. 异常处理困难

Python高级知识点学习(九)相关推荐

  1. Python高级知识点学习(一)

    image.png Python中一切皆对象 和Java相比,Python的面向对象更加彻底. 函数和类也是对象,是python的一等公民. 代码和模块也可以称之为对象. python中的类也是对象, ...

  2. 郑州学python_郑州Python基础知识点学习之内置类型

    想要学好Python,一定要学好各类知识点,比如类.对象.数据类型等.有部分同学对于内置类型概念模糊,接下来千锋小编分享的郑州Python基础知识点汇总就给大家简单梳理一下. 内置类型是指任何语言在设 ...

  3. Python高级知识点汇总第一部

    Linux常见命令 ls:查看当前路径下的所有文件及文件名; clear:清空操作; cd 跳转操作,可以跳转到任意路径位置; cd-:跳转到上次所在的路径; cd~:快速切换到当前用户的主目录(快速 ...

  4. python知识点总结全_【转】Python高级知识点总结

    一.可迭代对象.迭代器对象和生成器 像list, tuple等这些序列是可以使用for...in ...语句来进行遍历输出的.这是为什么呢?这就需要知道可迭代对象(Iterable).迭代器对象(It ...

  5. python网络平台_python学习(九) 网络编程学习--简易网站服务器

    python `网络编程`和其他语言都是一样的,服务器这块步骤为: `1. 创建套接字` `2. 绑定地址` `3. 监听该描述符的所有请求` `4. 有新的请求到了调用accept处理请求` Pyt ...

  6. c++面向对象高级编程 学习九 pointer-like classes

    c++的class设计出来有两种形式,一种像指针,一种像函数 智能指针里包含普通指针,要写 * 和 -> 的函数 sp->method(); //sp-> 经 T* operator ...

  7. 怎样学好python编程-怎样学习python编程?

    什么是Python? 在过去的2017年里,Python开发者在全球快速增长,国内小伙伴学习 Python 的热情一路高涨.同时,PYPL发布7月编程语言指数榜,Python 在今年5月首次超越 Ja ...

  8. Python学习笔记(五) Python高级特性

    Python高级特性 一. 切片 python中提供了切片(Slice)操作符 , 可以方便的获取list或tuple中的某一段元素 . # -*- coding : utf-8 -*- #Pytho ...

  9. 强烈推荐这11个Python开源项目,非常值得入门学习(从入门到Python高级开发)

    Python的日益普及及其在业界的使用使它成为当今最流行的编程语言之一.即使有很多学习Python的资源,例如参考书,视频教程,网站,您也可以将GitHub视为满足学习Python愿望的可靠资源之一. ...

最新文章

  1. 用无人车硬件玩GTA 5,这个12岁孩子的外挂有点硬核
  2. javascript中的表结构
  3. mstem函数怎么定义_PYTHON--函数定义
  4. android - 常用知识点以及代码片段(不断更新)
  5. 本科毕设论文——基于Kinect的拖拉机防撞系统
  6. 腾讯信息流推荐业务实践:内容分发场景的多目标架构实践
  7. Java 连接 SQL Server 数据库
  8. 描绘质量属性的六个常见属性场景。
  9. 别催更啦!手淘全链路性能优化下篇--容器极速之路
  10. 手工做迷宫_手工DIY好玩双人大型立体迷宫玩具
  11. 最牛逼的PHP视频教程115网盘免费下载,嗷嗷给力
  12. 所有安卓手机通刷原生系统
  13. iOS xcode中生成和打包ipa文件的方法和步骤
  14. 一种简单的仓储系统实物可视化分布实现方案
  15. 树莓派 11 bullseye镜像官方源和国内源
  16. sqlserver2012用ip远程连接设置
  17. 深入浅出低功耗蓝牙(BLE)协议栈,使用Ubertooth one扫描嗅探低功耗蓝牙
  18. Linux学习总结(59)——为什么建议大家使用 Linux 开发
  19. Mac 修改AppleID 使用“登录”钥匙串
  20. web免登钉钉微应用

热门文章

  1. 如何快速的入门Docker并且实现部署
  2. git 子模块_Git子模块的问题
  3. 桩位编号插件xzbh_饶平专业泵站基坑拉森钢板桩施工规范
  4. brew安装php-ffmpeg,mac 系统编译安装ffmpeg
  5. 哈斯机床进去debug模式_责任链模式
  6. arraylist扩容是创建新数组吗 java_Java集合干货——ArrayList源码分析
  7. Tomcat 5 5 JNDI Resource 配置
  8. 快速编写json数据
  9. 错误Cannot resolve org.springframework.data:spring-data-redis:2.2.6 RELEASE
  10. Java学习笔记2.2.1 常量与变量 - 变量