协程,IO模式

1、协程(别人的模块,达到单线程并发效果)

程序的运行状态:

阻塞:

IO阻塞

非阻塞:

运行

就绪

单线程实现并发:

在应用程序里控制多个任务的切换+保存状态

可以把IO减下来,但是不可能降到无

优点:

应用程序级别速度要远远高于操作系统的切换

缺点:

多个任务一旦有一个阻塞没有切,整个县城都堵塞在原地

该线程内的其他的任务都不能执行

一旦引入协程,就需要检测单线程下素有的IO行为,

实现遇到IO就切换,少一个都不行,因为一旦一个任务阻塞,整个线程就 阻塞,其他的任务即便是可以计算,但是也无法运行。

2、用协程的目的

想要在单线程下实现并发

并发指的是多个任务看起来是同时运行的

并发=切换+保存状态

线程在进程内,进程在操作系统内,一切由操作系统控制

自己设置python程序让线程形成切换,不用操作系统控制。

协程只有单线程下遇到IO切换才会提成效率,操作系统相对与协程要更慢点

import time

def func1():
    for i in range(1000000):
        i+1
def func2():
    for i in range(1000000):
        i+1
start = time.time()
func1()
func2()
stop=time.time()
print(stop-start)

# 基于yield并发
import time
def func1():
    while True:
        print("func1")
        yield
def func2():
    g=func1()
    for i in range(1000000):
        print("func2")
        i+1
        time.sleep(3)
        next(g)

start=time.time()
func2()
stop=time.time()
print(stop-start)
串行执行:
from gevent import monkey,spawn;monkey.patch_all()#monkey.patch_all()补丁
import time

def eat(name):
    print("%s eat 1" %name)
    time.sleep(3)
    print("%s eat 2" %name)
def play(name):
    print("%s play 1" %name)
    time.sleep(1)
    print("%s play 2" %name)

start=time.time()
g1=spawn(eat,"yf")#自动运行任务 模块
g2=spawn(play,"fxc")

g1.join()#通过补丁让join识别其他IO
g2.join()
print(time.time() - start)
print(g1)
print(g2)


from gevent import monkey,spawn;monkey.patch_all()
from threading import current_thread
import time

def eat(name):
    print("%s eat 1" %current_thread().name)#都是一个线程,前面有dummy假标明
    time.sleep(3)
    print("%s eat 2" %current_thread().name)
def play(name):
    print("%s play 1" %current_thread().name)
    time.sleep(1)
    print("%s play 2" %current_thread().name)

start=time.time()
g1=spawn(eat,"yf")
g2=spawn(play,"fxc")

g1.join()
g2.join()
print(time.time() - start)
print(g1)
print(g2)
与yield类似可以直接计算的 gevent

并发的套接字通信:

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 *

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:

    recvfrom:#等待客户链接请求

        wait data:等待客户端产生数据——》客户端OS--》网络--》服务端操作系统缓存

        copy data:由本地操作系统缓存中的数据拷贝到应用程序的内存中

    send:

        copy data

conn.recv(1024) ==>OS

from socket import *
import time

server = socket()
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)
服务端:
from socket import *
import os

client=socket(AF_INET,SOCK_STREAM)
client.connect(("127.0.0.1",8080))
while True:
    msg="%s say hello" %os.getpid()
    client.send(msg.encode("utf-8"))
    data=client.recv(1024)
    print(data.dacoda("utf-8"))
客户端:

猜你喜欢

转载自www.cnblogs.com/yf18767106368/p/9325944.html