python协程和异步IO

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实列

 1 import selectors,socket
 2 def accept(sock, mask):
 3     conn, addr = sock.accept()
 4     print('accepted{}from{}'.format(conn,addr))
 5     conn.setblocking(False)
 6     sel.register(conn,selectors.EVENT_READ, read)
 7 
 8 def read(conn, mask):
 9     data = conn.recv(1024)
10     if data:
11         print('echoing{}to{}'.format(repr(data),conn))
12     else:
13         print('closing',conn)
14         sel.unregister(conn)
15         conn.close()
16 sel = selectors.DefaultSelector()
17 server = socket.socket()
18 server.bind(('localhost', 9999))
19 server.listen(500)
20 server.setblocking(False)
21 sel.register(server, selectors.EVENT_READ, accept) #注册事件,只要来一个连接就调accept这个函数,
22 
23 while True:
24     events = sel.select()#这个select,看起来是select,有可能调用的是epoll,看你操作系统是Windows的还是Linux的
25                            #默认阻塞,有活动连接就返回活动连接列表
26     print('事件',events)
27 
28     for key,mask in events:
29         callback = key.data
30         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()

猜你喜欢

转载自www.cnblogs.com/gaosie/p/10829065.html
今日推荐