IO多路复用和local概念
一、local
在多个线程之间使用threading.local对象,可以实现多个线程之间的数据隔离 import time
import random
from threading import Thread,local loc = local() def func1():
global loc
print(loc.name,loc.age) def func2(name,age):
global loc
loc.name = name
loc.age = age
time.sleep(random.uniform(0,2))
func1() Thread(target=func2,args=('明哥',19)).start()
Thread(target=func2,args=('小弟',17)).start() 结果:
小弟 17
明哥 19 解释:
在平时的线程中,应该每次打印的结果应该都是最后进来的线程的数据,即第一次的数据会被第二次的数据覆盖,
但是使用了local对象,可以实现线程的数据隔离,因此打印的两次结果都不一样。 原理:
local对象会创建一个大字典,字典的键是线程的id,值也是一个字典,存储数据,例如: {
线程id1:{'name':'明哥',age:19}
线程id2:{'name':'小弟',age:17}
...
} 二、
1、阻塞IO(blocking IO)
当用户进程调用了recv/recvfrom这些系统调用时,操作系统就开始了IO的第一个阶段:准备数据。因为很多时候数据一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候操作系统就要等待足够的数据到来。
而在用户进程这边,整个进程会被阻塞。操作系统一直等到数据准备好了,它就会将数据拷贝到用户内存,然后返回结果,用户进程才解除block的状态,重新运行起来。
所以,blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了。 几乎所有的程序员第一次接触到的网络编程都是从listen()、send()、recv() 等接口开始的,使用这些接口可以很方便的构建服务器/客户机的模型。然而大部分的socket接口都是阻塞型的。
阻塞型接口是指系统调用(一般是IO接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。
实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。 解决方案:
在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。 该方案的问题是:
开启多进程或都线程的方式,在遇到要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,降低系统对外界响应效率,而且线程与进程本身也更容易进入假死状态。 改进方案:
很多程序员可能会考虑使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如websphere、tomcat和各种数据库等。 改进后方案其实也存在着问题:
“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用IO接口带来的资源占用。而且,所谓“池”始终有其上限,当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,并根据响应规模调整“池”的大小。 对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型也会遇到瓶颈,可以用非阻塞接口来尝试解决这个问题。 2、非阻塞IO
非阻塞IO操作一些时,如果操作系统中的数据还没有准备好,它也不会出现阻塞,而是立刻返回一个error。用户进程可以判断这个返回值是否是error,如果是它就知道数据还没有准备好,于是用户就可以在下次询问前的时间内做其他事情。如果数据准备好了,且用户再次进行询问时,那么数据就可以拷贝到用户内存(这一阶段仍然是阻塞的),然后返回。
其实在非阻塞式IO中,用户进程其实是需要不断的主动询问操作系统数据是否准备好了。 例如:
Server端:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.setblocking(False) # 设置当前的server为一个非阻塞IO模型
sk.listen() conn_lst = []
del_lst = [] while True:
try:
conn,addr = sk.accept()
conn_lst.append(conn)
except BlockingIOError:
for conn in conn_lst:
try:
conn.send(b'hello')
print(conn.recv(1024))
except (NameError,BlockingIOError):pass
except ConnectionResetError:
conn.close()
del_lst.append(conn)
for del_conn in del_lst:
conn_lst.remove(del_conn)
del_lst.clear() Client端:
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080)) while 1:
print(sk.recv(1024))
sk.send(b'heiheihei') 这样就可以实现非阻塞IO下基于TCP的并发socket,
但是这样的非阻塞IO大量的占用了CPU导致了资源的浪费并且给CPU造成了很大的负担 3、多路复用IO
当用户进程调用了select,那么整个进程会被block,同时,操作系统会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从操作系统拷贝到用户进程。 多路复用IO与阻塞IO:
多路复用IO需要使用两次系统调用,而阻塞IO只调用了一个系统调用。但是,用select的优势在于它可以同时处理多个连接,而阻塞IO只能处理一个。 例子:
Server端:
import select # 用来操作操作系统中的select(IO多路复用)机制
import socket sk = socket.socket()
sk.bind(('127.0.0.1',8888))
sk.setblocking(False)
sk.listen() r_lst = [sk,] while True:
# 监视r_lst这个列表(所有待接收请求的对象都在这里),谁的请求来了就通知谁,然后把有请求的对象返回给r_l列表,也有可能两个请求一起来
r_l,_,_ = select.select(r_lst,[],[])
for item in r_l: # 循环有请求的对象,判断是什么类型,进行对应的操作
if item is sk:
conn,addr = sk.accept()
r_lst.append(conn)
else:
try:
print(item.recv(1024))
item.send(b'hello')
except ConnectionResetError:
item.close()
r_lst.remove(item) Client端:
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8888))
while 1:
sk.send(b'world')
print(sk.recv(1024)) 多路复用IO小结:
io多路复用(asycio tornado twisted)机制
select 在windows\mac\linux可用
底层是操作系统的轮询
有监听对象个数的限制
随着监听对象的个数增加,效率降低
poll 只在mac\linux可用
底层是操作系统的轮询
有监听对象个数的限制,但是比select能监听的个数多
随着监听对象的个数增加,效率降低
epoll 只在mac\linux可用
给每一个要监听的对象都绑定了一个回调函数
不再受到个数增加 效率降低的影响 socketserver机制
IO多路复用 + threading线程 selectors模块
帮助你在不同的操作系统上进行IO多路复用机制的自动筛选 4、异步IO(Asynchronous I/O)
用户进程发起请求之后,操作系统会立刻返回,所有不会形成阻塞,然后用户进程立刻就可以开始去做其它的事。同时操作系统会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,会给用户进程发送一个signal,告诉它操作完成了。
IO多路复用和local概念的更多相关文章
- linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例
除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnblogs.com/Anker/p/3265058.html 最简单的select示例: #incl ...
- linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例【转】
转自:https://www.cnblogs.com/welhzh/p/4950341.html 除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnb ...
- Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型
Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...
- 进击的Python【第十章】:Python的高级应用(多进程,进程间通信,协程与异步,牛逼的IO多路复用)
Python的socket高级应用(多进程,协程与异步) 一.多进程multiprocessing multiprocessing is a package that supports spawnin ...
- IO多路复用技术总结
来源:微信公众号「编程学习基地」 IO 多路复用概述 I/O 多路复用技术是为了解决进程或线程阻塞到某个 I/O 系统调用而出现的技术,使进程不阻塞于某个特定的 I/O 系统调用. 在IO多路复用技术 ...
- IO多路复用概念性
sellect.poll.epoll三者的区别 先来了解一下什么是进程切换 为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行,这种行为为进程的切换,任务切换 ...
- IO多路复用之select总结
1.基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程.IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/ ...
- 【知乎网】Linux IO 多路复用 是什么意思?
提问一: Linux IO多路复用有 epoll, poll, select,知道epoll性能比其他几者要好.也在网上查了一下这几者的区别,表示没有弄明白. IO多路复用是什么意思,在实际的应用中是 ...
- Python自动化之IO多路复用
单线程.多线程和异步对比图 灰色的是阻塞 IO多路复用 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心 ...
随机推荐
- java泛型-泛型类,泛型接口,常用形式
泛型简单使用: package com.etc; import java.util.ArrayList; import java.util.List; /* 泛型就相当于<>一个标签,泛化 ...
- Axure rp8团队原型图开发
说道原型图大家都不陌生,Axure rp作为这类工具可以说在网页布局的设计给开发人员提供了很大便利,目前我只熟悉过这一种,不知道小伙伴们有没有其他好用的工具推荐给大家用一下吗.好了,废话不多说,今天给 ...
- JSON WEB TOKEN(JWT)的分析
JSON WEB TOKEN(JWT)的分析 一般情况下,客户的会话数据会存在文件中,或者引入redis来存储,实现session的管理,但是这样操作会存在一些问题,使用文件来存储的时候,在多台机器上 ...
- SQL Server中几种遍历方式比较
SQL遍历解析 在SQL的存储过程,函数中,经常需要使用遍历(遍历table),其中游标.临时表等遍历方法很常用.面对小数据量,这几种遍历方法均可行,但是面临大数据量时,就需要择优选择,不同的遍历方法 ...
- 什么是基于风险的测试(RBT)?
基于风险的测试(Risk-based testing) 文/杨学明 一.基于风险的测试起源 基于风险的测试起源,在软件测试领域,基于风险测试最早的是测试大师Boris Beizer<软件测试技术 ...
- 转摘app测试方法总结
app测试方法总结 一.安全测试 1.软件权限 1)扣费风险:包括短信.拨打电话.连接网络等. 2)隐私泄露风险:包括访问手机信息.访问联系人信息等. 3)对App的输入有效性校验.认证.授权.数 ...
- Linux 中磁盘容量配额
linux的设计之处就是为了多用户同时执行不同的任务,但是硬件资源是有限的,不能让一个用户无限制的上传文件,如果不加以限制,那么磁盘最终将会被充满,对此我们应该使用uquota来加以限制. 1.quo ...
- c/c++ 头文件的血案
头文件的血案 不小心在一个头文件里,加了函数的定义,结果导致编译时,提示这个函数被重复定义:( Quote.h #ifndef __QUOTE_H__ #define __QUOTE_H__ #inc ...
- Linux学习历程——Centos 7 touch命令
一.命令介绍 touch 命令用于创建空白文件,以及设置文件的时间. ----------------------------------------------------------------- ...
- java8 快速实现List转map 、分组、过滤等操作
利用java8新特性,可以用简洁高效的代码来实现一些数据处理. 定义1个Apple对象: public class Apple { private Integer id; private String ...