1. 并发, 并行, 同步, 异步, 阻塞, 非阻塞
并发: 是指在同一个时间段内, 有几个程序都处于启动运行到运行结束之间
并行: 在同一个时间点上, 有几个程序同时运行
同步: 当一个同步操作发出去后, 调用者一直等待返回消息结果, 才能进行后续的操作 比如操作文件 打开文件 读取文件 都是同步操作
异步: 当一个异步操作发出去后, 调用者不能立刻得到消息结果 创建线程 都是异步操作
阻塞: 调用结果返回之前, 当前线程会被挂起来, 一直处于等待消息通知, 不能执行其他业务
非阻塞: 调用结果返回之前, 该函数不会阻塞当前线程 而立刻返回
2.IO 多路复用 select,poll,epoll
select
它通过一个 select()系统调用来监视多个文件描述符, 当 select()返回后, 该数组中就绪的文件描述符会被内核修改标志位, 使进程能够获得这些文件描述符, 从 而进行后续的修改
缺点: 单个进程能够监视的文件描述符的数量存在最大限制 一般 1024
poll
本质跟 select()没有区别 但是 poll 没有限制, 使用的是链表存储
epoll
epoll 同样只告知那些就绪的文件描述符, 而且当我们调用 epoll_wait()获得就绪文件描述符时, 返回的不是实际的描述符, 而是一个代表就绪描述符数量的 值, 你只需要去 epoll 指定的一个数组中依次取得相应数量的文件描述符即可, 这里也使用了内存映射 (mmap) 技术, 这样便彻底省掉了这些文件描述符 在系统调用时复制的开销.
另一个本质的改进在于 epoll 采用基于事件的就绪通知方式. 在 select/poll 中, 进程只有在调用一定的方法后, 内核才对所有监视的文件描述符进行扫描, 而 poll 事先通过 epoll_ctl()来注册一个文件描述符, 一旦基于某个文件描述符就绪时, 内核会采用类似 callback 的回调机制, 迅速激活这个文件描 述符, 当进程调用 epoll_wait()时便得到通知.
epoll 实列
- import selectors,socket
- def accept(sock, mask):
- conn, addr = sock.accept()
- print('accepted{}from{}'.format(conn,addr))
- conn.setblocking(False)
- sel.register(conn,selectors.EVENT_READ, read)
- def read(conn, mask):
- data = conn.recv(1024)
- if data:
- print('echoing{}to{}'.format(repr(data),conn))
- else:
- print('closing',conn)
- sel.unregister(conn)
- conn.close()
- sel = selectors.DefaultSelector()
- server = socket.socket()
- server.bind(('localhost', 9999))
- server.listen(500)
- server.setblocking(False)
- sel.register(server, selectors.EVENT_READ, accept) #注册事件, 只要来一个连接就调 accept 这个函数,
- while True:
- events = sel.select()# 这个 select, 看起来是 select, 有可能调用的是 epoll, 看你操作系统是 Windows 的还是 Linux 的
- #默认阻塞, 有活动连接就返回活动连接列表
- print('事件',events)
- for key,mask in events:
- callback = key.data
- callable(key.fileobj, mask)
- View Code
客户端
- import socket,sys
- server_address = ('localhost', 9999)
- # 创建 100 个 TCP/IP socket 实例
- socks = [ socket.socket(socket.AF_INET, socket.SOCK_STREAM) for i in range(100)]
- # 连接服务端
- print('connecting to %s port %s' % server_address)
- for s in socks:
- s.connect(server_address)
- s.send(b'kehuduan')
- data = s.recv(1024)
- print('服务端回来的数据{}'.format(data))
- if not data:
- print('连接失败')
- s.close()
来源: http://www.bubuko.com/infodetail-3050577.html