协程与IO模型

一。协程
1、协程:
    单线程实现并发
    在应用程序里控制多个任务的切换+保存状态
    优点:
        应用程序级别速度要远远高于操作系统的切换
    缺点:
        多个任务一旦有一个阻塞没有切,整个线程都阻塞在原地
        该线程内的其他的任务都不能执行了

        一旦引入协程,就需要检测单线程下所有的IO行为,
        实现遇到IO就切换,少一个都不行,以为一旦一个任务阻塞了,整个线程就阻塞了,
        其他的任务即便是可以计算,但是也无法运行了

2、协程序的目的:
    想要在单线程下实现并发
    并发指的是多个任务看起来是同时运行的
    并发=切换+保存状态

二。导入模块来实现单线程并发

利用gevent来实现单线程并发
导入monkey.patch_all()来实现所有的IO都可以识别
from gevent import monkey,spawn;monkey.patch_all()
from threading import current_thread
import time

def eat():
    print('%s eat 1' %current_thread().name)
    time.sleep(3)
    print('%s eat 2' %current_thread().name)

def play():
    print('%s play 1' %current_thread().name)
    time.sleep(1)
    print('%s play 2' %current_thread().name)

g1=spawn(eat,)
g2=spawn(play,)

print(current_thread().name)

三,单线程下实现并发的套接字
服务端
from gevent import spawn,monkey;monkey.patch_all()
from socket import *
from threading import Thread

def talk(conn):
    while True:
        try:
            data=conn.recv(1024)
            if len(data) == 0:break
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()

def server(ip,port,backlog=5):
    server = socket(AF_INET, SOCK_STREAM)
    server.bind((ip, port))
    server.listen(backlog)

    print('starting...')
    while True:
        conn, addr = server.accept()
        spawn(talk, conn,)

if __name__ == '__main__':
    g=spawn(server,'127.0.0.1',8080)
    g.join()

客户端
from threading import Thread,current_thread
from socket import *
import os

def task():
    client=socket(AF_INET,SOCK_STREAM)
    client.connect(('127.0.0.1',8080))

    while True:
        msg='%s say hello' %current_thread().name
        client.send(msg.encode('utf-8'))
        data=client.recv(1024)
        print(data.decode('utf-8'))

if __name__ == '__main__':
    for i in range(500):
        t=Thread(target=task)
        t.start()

IO模型的介绍
网络IO:
    recvfrom:
        wait data:等待客户端产生数据——》客户端OS--》网络--》服务端操作系统缓存
        copy data:由本地操作系统缓存中的数据拷贝到应用程序的内存中

    send:
        copy data




非阻塞IO模型
服务端
from socket import *
import time

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False)

conn_l=[]
while True:
    try:
        print('总连接数[%s]' % len(conn_l))
        conn,addr=server.accept()
        conn_l.append(conn)
    except BlockingIOError:
        del_l=[]
        for conn in conn_l:
            try:
                data=conn.recv(1024)
                if len(data) == 0:
                    del_l.append(conn)
                    continue
                conn.send(data.upper())
            except BlockingIOError:
                pass
            except ConnectionResetError:
               del_l.append(conn)

        for conn in del_l:
            conn_l.remove(conn)





猜你喜欢

转载自blog.csdn.net/qq_35540539/article/details/81087474