python 并发编程 阻塞IO模型原理解析


Posted in Python onAugust 20, 2019

阻塞IO(blocking IO)

在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:

当用户进程调用了recvfrom这个系统调用,kernel内核就开始了IO的第一个阶段:准备数据。对于network io( 网络io )来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel( 内核 )就要等待足够的数据到来。

等着对方把数据放到自己操作系统内存

而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel操作系统缓存中拷贝到用户应用程序内存,

然后kernel返回结果,用户进程才解除block的状态,重新运行起来。

这就是阻塞IO

所以,blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了

网络编程都是从listen\(\)、send\(\)、recv\(\) 等接口开始的,
使用这些接口可以很方便的构建服务器/客户机的模型。然而大部分的socket接口都是阻塞型的。如下图

ps:

所谓阻塞型接口是指系统调用(一般是IO接口)不返回调用结果并让当前线程一直阻塞
只有当该系统调用获得结果或者超时出错时才返回。

服务端:

from socket import *
server = socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8000))
server.listen(5)
while True:
  print("starting...")
  conn,addr = server.accept()
  print(addr)
  while True:
    try:
      data = conn.recv(1024)
      if not data:break
      conn.send(data.upper())
    except ConnectionResetError:
      break
server.close()

客户端

from socket import *
client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8000))
while True:
  msg = input(">>>:").strip()
  if not msg:continue
  client.send(msg.encode("utf-8"))
  data = client.recv(1024)
  print(data.decode("utf-8"))
client.close()

python 并发编程 阻塞IO模型原理解析

实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。

一个简单的解决方案:

在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),
这样任何一个连接的阻塞都不会影响其他的连接。

该方案的问题是 :

开启多进程或都线程的方式,在遇到要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,
降低系统对外界响应效率,而且线程与进程本身也更容易进入假死状态。
随着客户端数量增多,无限制的开线程,开销非常大
不能解决阻塞IO问题 ,解决思路:起多线程

改进方案:

使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,
其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、
减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如websphere、tomcat和各种数据库等。

改进后方案其实也存在着问题:

“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且,所谓“池”始终是有限,
当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,

并根据响应规模调整“池”的大小。

线程池应该随着规模数调大,但是调大线程池,要在机器可承受范围之内。不能把线程池无限调大,这样相当于无限开线程一样,

多线程还是要用在规模比较小的情况

对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型也会遇到瓶颈,可以用非阻塞接口来尝试解决这个问题。

总结:

始综没有解决单线程遇到IO问题,单线程遇到IO,就阻塞,用的是阻塞IO模型。

阻塞IO模型就是遇到IO阻塞不处理,就在原地等着。

应该:

监测单线程IO,遇到IO了,这个线程不要阻塞。直接切换到另外一个线程运行,这样单线程效率就非常高了。

要解决的问题是:

单线程IO问题

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
编写Python脚本使得web页面上的代码高亮显示
Apr 24 Python
举例讲解Python编程中对线程锁的使用
Jul 12 Python
python装饰器初探(推荐)
Jul 21 Python
python常见排序算法基础教程
Apr 13 Python
Django的信号机制详解
May 05 Python
python3+PyQt5实现文档打印功能
Apr 24 Python
python email smtplib模块发送邮件代码实例
Apr 26 Python
python处理DICOM并计算三维模型体积
Feb 26 Python
python 将字符串中的数字相加求和的实现
Jul 18 Python
django 单表操作实例详解
Jul 30 Python
OpenCV4.1.0+VS2017环境配置的方法步骤
Jul 09 Python
 python中的元类metaclass详情
May 30 Python
PyTorch中常用的激活函数的方法示例
Aug 20 #Python
Pytorch抽取网络层的Feature Map(Vgg)实例
Aug 20 #Python
python批量解压zip文件的方法
Aug 20 #Python
pytorch获取vgg16-feature层输出的例子
Aug 20 #Python
python 并发编程 非阻塞IO模型原理解析
Aug 20 #Python
Python实现某论坛自动签到功能
Aug 20 #Python
python函数的作用域及关键字详解
Aug 20 #Python
You might like
DOTA2 玩家自创拉野攻略 特色英雄快速成长篇
2020/04/20 DOTA
php录入页面中动态从数据库中提取数据的实现
2006/10/09 PHP
mysql,mysqli,PDO的各自不同介绍
2012/09/19 PHP
完善CodeIgniter在IDE中代码提示功能的方法
2014/07/19 PHP
PHP中上传多个文件的表单设计例子
2014/11/19 PHP
深入理解PHP中的Streams工具
2015/07/03 PHP
php时间函数用法分析
2016/05/28 PHP
thinkPHP中钩子的使用方法实例分析
2017/11/16 PHP
Laravel配合jwt使用的方法实例
2020/10/25 PHP
ExtJs 3.1 XmlTreeLoader Example Error
2010/02/09 Javascript
jquery form表单提交插件asp.net后台中文解码
2010/06/12 Javascript
javascript打印大全(打印页面设置/打印预览代码)
2013/03/29 Javascript
js中的scroll和offset 使用比较的实例与分析
2013/09/29 Javascript
jQuery获取标签文本内容和html内容的方法
2015/03/27 Javascript
javascript入门教程基础篇
2015/11/16 Javascript
js父页面中使用子页面的方法
2016/01/09 Javascript
jQuery实现两列等高并自适应高度
2016/12/22 Javascript
IE11下使用canvas.toDataURL报SecurityError错误的解决方法
2017/11/19 Javascript
JS+WCF实现进度条实时监测数据加载量的方法详解
2017/12/19 Javascript
JavaScript Math对象和调试程序的方法分析
2019/05/13 Javascript
详解vue中v-model和v-bind绑定数据的异同
2020/08/10 Javascript
python根据给定文件返回文件名和扩展名的方法
2015/03/27 Python
Python多线程编程(二):启动线程的两种方法
2015/04/05 Python
Python基于DES算法加密解密实例
2015/06/03 Python
python分治法求二维数组局部峰值方法
2018/04/03 Python
TensorFlow损失函数专题详解
2018/04/26 Python
Random 在 Python 中的使用方法
2018/08/09 Python
python实现人脸签到系统
2020/04/13 Python
HTML5 Canvas 旋转风车绘制
2017/08/18 HTML / CSS
Interflora澳大利亚:同日鲜花速递
2019/06/25 全球购物
Java Servlet的主要功能和作用是什么
2014/02/14 面试题
师范生自我鉴定
2014/03/20 职场文书
捐助倡议书范文
2014/04/15 职场文书
党员自我评议个人对照检查材料
2014/09/16 职场文书
Python中OpenCV实现简单车牌字符切割
2021/06/11 Python
MySQL数据库之存储过程 procedure
2022/06/16 MySQL