并发编程/IO模型

背景概念

IO模型概念

IO模型分类

阻塞IO  (blocking IO)

特点

    两个阶段(等待数据和拷贝数据两个阶段)都被block

设置

server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

解决方案: 

    启用多线程或者多进程,要阻塞只阻塞当前线程/进程,不会影响其他进程/线程

不良影响:

    当遇到过多得链接请求时会严重占用资源,降低响应效率

修复不良影响:

    启用进程池/线程池 ,降低进程/线程数量

 仍旧未解决的不良影响:

    池得数量不好规范,请求数量和池大小不好对应,且池存在数量上限

    只是一定程度上限制了不良影响,无法根本解决

  总结 :

    基于池得创建可以解决小规模得服务请求带来的压力,对于大规模还是无力回天

非阻塞IO  (nonblocking IO)

  特点

    基于IO阻塞模型类似,再本应阻塞得地方不在阻塞,如果未收到想要数据会返回一个 error 给用户告知无数据

    发送 error 后会进行其他得任务继续操作背后会一直对 kernel 进行轮询发送数据请求,

    这期间如果数据到了就会重新正常操作,而在轮询期间,无数据得进程会一直处于阻塞状态

    就结果而言。完全得实现了并发,以及解决了IO阻塞带来得效率低下的问题

设置

server.setblocking()    #默认是True
server.setblocking(False) #False的话就成非阻塞了,这只是对于socket套接字来说的

不良影响:

    1. 虽说解决了单线程并发,但是大大的占用了cpu

    2.  任务完成的响应延迟增大,任务可能在两次轮询之间的任意时间完成。这会导致整体数据吞吐量的降低

  总结 :

    完全不推荐

多路复用IO  (IO multiplexing)

  特点

    当用户进程调用了select,那么整个进程会被block

    而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。

    这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

    这个图和blocking IO的图其实并没有太大的不同,事实上还更差一些。

    因为这里需要使用两个系统调用(select和recvfrom),而blocking IO只调用了一个系统调用(recvfrom)。但是,用select的优势在于它可以同时处理多个connection。

设置

使用 select 模块 或者 eppol (只能用于 linux 中)
最优的选择方案是用 selectors

    selectors 实例 

#服务端
from socket import *
import selectors sel=selectors.DefaultSelector()
def accept(server_fileobj,mask):
conn,addr=server_fileobj.accept()
sel.register(conn,selectors.EVENT_READ,read) def read(conn,mask):
try:
data=conn.recv(1024)
if not data:
print('closing',conn)
sel.unregister(conn)
conn.close()
return
conn.send(data.upper()+b'_SB')
except Exception:
print('closing', conn)
sel.unregister(conn)
conn.close() server_fileobj=socket(AF_INET,SOCK_STREAM)
server_fileobj.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server_fileobj.bind(('127.0.0.1',8088))
server_fileobj.listen(5)
server_fileobj.setblocking(False) #设置socket的接口为非阻塞
sel.register(server_fileobj,selectors.EVENT_READ,accept) #相当于网select的读列表里append了一个文件句柄server_fileobj,并且绑定了一个回调函数accept while True:
events=sel.select() #检测所有的fileobj,是否有完成wait data的
for sel_obj,mask in events:
callback=sel_obj.data #callback=accpet
callback(sel_obj.fileobj,mask) #accpet(server_fileobj,1) #客户端
from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',8088)) while True:
msg=input('>>: ')
if not msg:continue
c.send(msg.encode('utf-8'))
data=c.recv(1024)
print(data.decode('utf-8'))

不良影响:

    1. 虽说解决了单线程并发,但是大大的占用了cpu

    2.  任务完成的响应延迟增大,任务可能在两次轮询之间的任意时间完成。这会导致整体数据吞吐量的降低

  总结 :

    select的优势在于可以处理多个连接,不适用于单个连接

异步IO(asynchronous IO)

  用户进程发起read操作之后,立刻就可以开始去做其它的事。

  kernel 受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。

  然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,

  当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

socketserver 模块

 包含类

  BaseServer是基类,它不能实例化使用,

  TCPServer使用TCP协议通信,

  UDPServer使用UDP协议通信,

  UnixStreamServer和UnixDatagramServer使用Unix域套接字,只适用于UNIX平台。

  ForkingMixIn 多进程异步

  ThreadingMixIn 多线程异步

如何创建一个socketserver :

  1. 创建一个请求处理的类,继承 BaseRequestHandlerclass ,要重写父类里 handle() 方法;

  2. 你必须实例化 TCPServer,并且传递server IP和你上面创建的请求处理类,给这个TCPServer;

  3. server.handle_requese()  只处理一个请求,server.server_forever() 处理多个一个请求,永远执行

  4. 关闭连接 server_close()

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler): #服务类,监听绑定等等

    def handle(self):  #请求处理类,所有请求的交互都是在handle里执行的
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()  #每一个请求都会实例化MyTCPHandler(socketserver.BaseRequestHandler):
print("{} wrote:".format(self.client_address[0]))
print(self.data)
self.request.sendall(self.data.upper())  #sendall是重复调用send. if __name__ == "__main__":
HOST, PORT = "localhost", 9999 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) # Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever() server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) #线程
# server = socketserver.ForkingTCPServer((HOST, PORT), MyTCPHandler) #多进程 linux适用
# server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) 单进程

ThreadingTCPServer

  服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。

import SocketServer

class MyServer(SocketServer.BaseRequestHandler):

    def handle(self):
pass if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8766), MyServer)
server.serve_forever()

ForkingTCPServer

  用法类似 ThreadingTCPServer 只是将线程换成了进程 

import SocketServer

class MyServer(SocketServer.BaseRequestHandler):

    def handle(self):
pass if __name__ == '__main__':
server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()

 总结:

socketserver 完美的解决了之前的各种困扰。不论是并发问题还是线程池大小以及IO问题都被解决。

  因此socketserver成为了最终解决方案

4.6 并发编程/IO模型的更多相关文章

  1. python 并发编程 io模型 目录

    python 并发编程 IO模型介绍 python 并发编程 socket 服务端 客户端 阻塞io行为 python 并发编程 阻塞IO模型 python 并发编程 非阻塞IO模型 python 并 ...

  2. Python Web学习笔记之并发编程IO模型

    了解新知识之前需要知道的一些知识 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调 ...

  3. Python之并发编程-IO模型

    目录 一.IO模型介绍二.阻塞IO(blocking IO)三.非阻塞IO(non-blocking IO)四.多路复用IO(IO multiplexing)五.异步IO(Asynchronous I ...

  4. 并发编程 - io模型 - 总结

    1.提交任务得方式: 同步:提交完任务,等结果,执行下一个任务 异步:提交完,接着执行,异步 + 回调 异步不等结果,提交完任务,任务执行完后,会自动触发回调函数2.同步不等于阻塞: 阻塞:遇到io, ...

  5. python并发编程&IO模型

    一 IO模型介绍 为了更好地了解IO模型,可先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(n ...

  6. 并发编程——IO模型

    前言 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回.按照这个定义, ...

  7. 并发编程——IO模型详解

    ​ 我是一个Python技术小白,对于我而言,多任务处理一般就借助于多进程以及多线程的方式,在多任务处理中如果涉及到IO操作,则会接触到同步.异步.阻塞.非阻塞等相关概念,当然也是并发编程的基础. ​ ...

  8. 15 并发编程-(IO模型)

    一.IO模型介绍 1.阻塞与非阻塞指的是程序的两种运行状态 阻塞:遇到IO就发生阻塞,程序一旦遇到阻塞操作就会停在原地,并且立刻释放CPU资源 非阻塞(就绪态或运行态):没有遇到IO操作,或者通过某种 ...

  9. 并发编程——IO模型(6)

    1.IO模型分类 同步IO #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回.按照这个定义,其实绝大多数函数都是同步调用.但是一般而言,我们在说同步.异步的时候,特指那些需要 ...

随机推荐

  1. 仿9GAG制作过程(四)

    有话要说: 这次主要讲述主页面下拉刷新和上拉加载功能的实现. 主要是使用了SwipeRefreshLayout的布局方式,并在此基础上通过RecyclerView的特性增加了上拉加载的功能. 成果: ...

  2. spring学习总结——装配Bean学习二(JavaConfig装配bean)

    通过Java代码装配bean 前言:上面梳理了通过注解来隐式的完成了组件的扫描和自动装配,下面来学习下如何通过显式的配置的装配bean: 使用场景:比如说,你想要将第三方库中的组件装配到你的应用中,在 ...

  3. 5.1Python数据处理篇之Sympy系列(一)---Sympy的大体认识

    目录 目录 前言 目录 前言 sympy是python一个强大的数学符号运算第三方库,具体的功能请看下面操作 官网教程: https://docs.sympy.org/latest/tutorial/ ...

  4. 戏说春秋_i春秋 writeup

    <戏说春秋>第一关 图穷匕见 题目: 解:用winhex打开,拉到最后可发现一段编码 放到解密网站上解码. <戏说春秋>第二关 纸上谈兵 解:文中没有明确指出问题,也没有给出线 ...

  5. 【Python 20】BMR计算器4.0(异常处理)

    1.案例描述 基础代谢率(BMR):我们安静状态下(通常为静卧状态)消耗的最低热量,人的其他活动都建立在这个基础上. 计算公式: BMR(男) = (13.7*体重kg)+(5.0*身高cm)-(6. ...

  6. vim之快速查找功能

    vim有强大的字符串查找功能. 我们通常在vim下要查找字符串的时候, 都是输入 / 或者 ?  加 需要查找的字符串来进行搜索,比如想搜索 super 这个单词, 可以输入  /super  或者 ...

  7. day6-基础函数的学习(一)

    今日份目录 1.函数的定义 2.函数的返回值 3.函数的参数 4.函数的局部变量与全局变量 5.名称空间与作用域 6.global与nonlocal 7.高阶函数 继续今日份总结!这个总结也晚了,哎, ...

  8. ksar、sar及相关内核知识点解析

    关键词:sar.sadc.ksar./proc/stat./proc/cpuinfo./proc/meminfo./proc/diskstats. 在之前有简单介绍过sar/ksar,最近在使用中感觉 ...

  9. C语言之四舍五入

    在C语言中,如果进行强制类型转换,它会将所需要取的位数直接提取出来,而其他位数的数字会被直接删除,不会对提取出来的位数有任何影响 所以如果我们需要提高精度,对所取的数进行四舍五入,需要给所需去的数的最 ...

  10. Reachability from the Capital CodeForces - 999E (强连通)

    There are nn cities and mm roads in Berland. Each road connects a pair of cities. The roads in Berla ...