day19-IO多路复用

1、I/O多路复用指:通过一种机制,可监听多个描述符(soket对象)(文件句柄),一旦某个描述符发送编号(一般指读就绪或写就绪),能够通知程序进行相应的读写操作。

2、I/O多路复用方式:select、poll 、epool。
win 只支持select
select:使用for循环,描述符最多1024个
pool:使用for循环实现,对文件描述符没有限制,
epoll:优化了实现方式,不在使用for循环,使用了异步的方式,效率高

2.1 select方式工作原理:

后面的1表示延时等待时间

nginx在内部就是基于epoll来实现的,使用epool+select来监听用户请求

2.2多路复用+socket实现伪并发处理示例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket
sk1 = socket.socket()
sk1.bind(('127.0.0.1', 8001))
sk1.listen()

# sk2 = socket.socket()
# sk2.bind(('127.0.0.1', 8002))
# sk2.listen()
#
# sk3 = socket.socket()
# sk3.bind(('127.0.0.1', 8003))
# sk3.listen()

# inputs = [sk1, sk2, sk3, ]
inputs = [sk1, ]
outputs = []
message_dict = {}
import select
while True:
    #[sk1,sk2, ],内部自动监听sk1, sk2 两个对象, 一旦某个句柄发生变化,就能感知到
    #如果有人连接 sk1
    #r_list = [sk1, ]
    #如果有人连接sk1发生编号
    r_list, w_list, e_list = select.select(inputs, outputs, inputs, 1)
    print("正在监听的socket对象总计:%d" % len(inputs))
    print(r_list)
    for sk1_or_conn in r_list:
        #每一个连接对象
        if sk1_or_conn == sk1:
            conn, address = sk1_or_conn.accept()
            inputs.append(conn)
            message_dict[conn] = []
        else:
            #有老用户发消息了
            try:
                data_bytes = sk1_or_conn.recv(1024)
                # data_str = str(data_bytes, encoding='utf-8')
                # sk1_or_conn.sendall(bytes(data_str+'好', encoding='utf-8'))
            except Exception as ex:
                #用户终止连接
                print(ex)
                inputs.remove(sk1_or_conn)
            else:
                #用户正常发送消息
                data_str = str(data_bytes, encoding='utf-8')
                message_dict[sk1_or_conn].append(data_str)
                # sk1_or_conn.sendall(bytes(data_str+'好', encoding='utf-8'))

                outputs.append(sk1_or_conn)
        # conn.sendall(bytes('hello',encoding='utf-8'))
        # conn.close()

    #w_list 仅仅保存了谁给我发过消息
    for conn in w_list:
        recv_str = message_dict[conn][0]
        del message_dict[conn][0]
        conn.sendall(bytes(recv_str+'', encoding='utf-8'))
        outputs.remove(conn)

    for sk1_or_conn in e_list:
        inputs.remove(sk1_or_conn)

# while True:
#     conn, address = sk.accept()
#     while True:
#         content_bytes = conn.recv(1024)
#         content_str = str(content_bytes, encoding='utf-8')
#         conn.sendall(bytes(content_str + '好', encoding='utf-8'))
#     conn.close()
server
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket

obj = socket.socket()

obj.connect(('127.0.0.1',8001 ))

while True:
    inp = input('>>>>>')
    obj.sendall(bytes(inp,encoding='utf-8'))
    ret = str(obj.recv(1024),encoding='utf-8')
    print(ret)


#
# content = str(obj.recv(1024),encoding='utf-8')
# print(content)
obj.close()
# #阻塞
# print('等待中')
# ret_bytes = obj.recv(1024)  #设置最高多接受的字节数,超过后需要等下次在接受
# print(str(ret_bytes,encoding='utf-8'))
# print('接受完成')
# # obj.close()
# while True:
#     inp = input('请输入要发送的内容(q退出)\n >>>')
#     if inp == 'q':
#         obj.sendall(bytes(inp,encoding='utf-8'))
#         break
#     else:
#         obj.sendall(bytes(inp,encoding='utf-8'))
#         ret = str(obj.recv(1024),encoding='utf-8')
#         print(ret)
# obj.close()
client
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import  socket
sk1 = socket.socket()
sk1.bind(('127.0.0.1', 8001))
sk1.listen()

sk2 = socket.socket()
sk2.bind(('127.0.0.1', 8002))
sk2.listen()

sk3 = socket.socket()
sk3.bind(('127.0.0.1', 8003))
sk3.listen()

inputs = [sk1, sk2, sk3, ]
import select
while True:
    #[sk1,sk2, ],内部自动监听sk1, sk2 两个对象, 一旦某个句柄发生变化,就能感知到
    #如果有人连接 sk1
    #r_list = [sk1]
    r_list, w_list, e_list = select.select(inputs, [], [], 1)
    for sk in r_list:
        #每一个连接对象
        conn, address = sk.accept()
        conn.sendall(bytes('hello',encoding='utf-8'))
        conn.close()

# while True:
#     conn, address = sk.accept()
#     while True:
#         content_bytes = conn.recv(1024)
#         content_str = str(content_bytes, encoding='utf-8')
#         conn.sendall(bytes(content_str + '好', encoding='utf-8'))
#     conn.close()
server-demo2

 

2.3关于并发

3、初始超线程

#!/usr/bin/envpython
#-*-coding:utf-8-*-
importthreading
importtime

defprocess(arg):
time.sleep(1)
print(arg)


#foriinrange(10):
#process(i)

foriinrange(10):
t=threading.Thread(target=process,args=(i,))
t.start()
demo

4、Soketserver原码解析

原理图

 5、初始多线程

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import  threading
import  time

def process(arg):
    time.sleep(1)
    print(arg)


# for i in range(10):
#     process(i)

for i in range(10):
    t = threading.Thread(target=process, args=(i,))
    t.start()
多线程