协程

协程

进程:资源单位

线程:执行单位

协程:单线程下实现并发(能够在多个任务之间切换和保存状态来节省IO)

多道技术:

  空间上的复用

  时间上的复用

核心:切换+保存状态

注意:

  操作系统的切换+保存状态是针对多个线程,

  想在单个线程下自己手动实现操作系统的切换+保存状态的功能,协程产生

  由于协程是程序员自己想出来并实现,它对于操作系统来说根本不存在。操作系统只知道进程和线程。

  需要注意的是:并不是单个线程下实现切换+保存状态就能提升效率,可能没有遇到io也切,那反而会降低效率

    任务是计算密集型,反而会降低效率

    任务是IO密集型,会提升效率

将单个线程的效率提升到最高,多进程下开多线程,多线程下用协程>>> 实现高并发!!! 

  1)yield能够实现保存上次运行状态,但是无法识别io

# 串行执行
import time


def func1():
    for i in range(10000000):
        i + 1


def func2():
    for i in range(10000000):
        i + 1


start = time.time()
func1()
func2()
stop = time.time()
print(stop - start)




# 基于yield并发执行
import time


def func1():
    while True:
        10000000 + 1
        yield


def func2():
    g = func1()
    for i in range(10000000):
        time.sleep(100)  # 模拟IO,yield并不会捕捉到并自动切换
        i + 1
        next(g)


start = time.time()
func2()
stop = time.time()
print(stop - start)
切换➕保存状态

2)单线程下实现并发

如果你能够自己通过代码层面监测你自己的io行为
并且通过代码实现切换+保存状态
单线程实现高并发
# ---------------服务端---------------------
from gevent import monkey; monkey.patch_all()
from gevent import spawn
import socket


def communicate(conn):
    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0: break
            print(data.decode('utf-8'))
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()


def server():
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    while True:
        conn, addr = server.accept()
        spawn(communicate, conn)


if __name__ == '__main__':
    s1 = spawn(server)
    s1.join()



# ---------------客户端---------------------
from threading import Thread, current_thread
import socket


def client():
    client = socket.socket()
    client.connect(('127.0.0.1', 8080))
    n = 1
    while True:
        data = '%s %s' % (current_thread().name, n)
        n += 1
        client.send(data.encode('utf-8'))
        info = client.recv(1024)
        print(info)


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

3)gevent模块的使用

  spawn:帮你管理任务的对象

  gevent模块不能识别它本身以外的所有的IO行为,但是它内部封装了一个模块,能够帮助我们识别所有的IO行为

from gevent import monkey; 
monkey.patch_all()  # 监测代码中所有io行为
from gevent import spawn
# gevent本身识别不了time.sleep等不属于该模块内的io操作
import time


def heng(name):
    print('%s 哼' % name)
    time.sleep(2)
    print('%s 哼' % name)


def ha(name):
    print('%s 哈' % name)
    time.sleep(3)
    print('%s 哈' % name)


start = time.time()
s1 = spawn(heng, 'Tom')
s2 = spawn(ha, 'Bob')

s1.join()
s2.join()
# heng('Tom')
# ha('Bob')

print('', time.time() - start)

 4)协程实现服务端客户端通信:socket并发

# 服务端
from gevent import monkey;monkey.patch_all()
from socket import *   # !!!后
from gevent import spawn


def communicate(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)

    while True:  # 链接循环
        conn, client_addr = server.accept()
        print(client_addr)

        # 通信
        spawn(communicate,conn)


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

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


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

    n = 0
    while True:
        msg = '%s say hello %s' % (current_thread().name, n)
        n += 1
        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=client)
        t.start()

5)IO模型 

阻塞IO  Blocking I/O
非阻塞IO
  服务端通信针对accept用s.setblocking(False)加异常捕获,cpu占用率过高
IO多路复用 multiplexing I/O
  在只检测一个套接字的情况下,他的效率连阻塞IO都比不上。因为select这个中间人增加了环节。
  但是在检测多个套接字的情况下,就能省去wait for data过程
异步IO  Asynchronous I/O
原文地址:https://www.cnblogs.com/zhouyongv5/p/10840282.html