python并发编程6-协程

1、基础

# 进程 启动多个进程 进程之间是由操作系统(时间片轮转)负责调用
# 线程 启动多个线程 真正被CPU执行的最小单位是线程
    # 开启一个线程 创建一个线程 寄存器 堆栈
    # 关闭一个线程  等都需要时间
# 协程:本质上是一个线程
    # 能够在多个任务之间切换来节省一些IO时间
    # 协程切换也需要时间,但是远远小于线程进程开销时间
# 实现并发的手段

2 协程应用背景

import time
'''1'''
def consumer():  # 生成器函数
    print(123)
    while True:
        x=yield
        print('**',x)
c=consumer()  # c为生成器,此时函数并没有执行
next(c)
c.send(1)

程序执行顺序:

程序运行结果:

3 在一个程序上进行两个任务的切换

'''2 在一个程序上进行两个任务的切换'''
def consumer():  # 生成器函数
    while True:
        x=yield
        time.sleep(1)
        print('处理了数据',x)
def producer():
    c=consumer()
    next(c)
    for i in range(3):
        time.sleep(1)
        print('生产了数据:',i)
        c.send(i)
producer()

程序执行顺序:

程序运行结果:

4、协程切换:切换后接着执行-greenlet模块

'''3 协程切换:切换后接着执行'''
from greenlet import greenlet
# 真正的协程模块就是使用greenlet完成的切换
def eat():
    print('eating start')
    g2.switch()
    print('eating end')
    g2.switch()
def play():
    print('playing start')
    g1.switch()
    print('playing end')
g1=greenlet(eat)
g2=greenlet(play)
g1.switch()

程序执行顺序:

程序执行结果:

5 协程切换 gevent

# spawn(func) 大量生产
# join()
# .value 得到方法的返回值

 例子1:

import gevent

def eat():
    print('eating start')
    gevent.sleep(1)
    print('eating end')
def play():
    print('playing start')
    gevent.sleep(1)
    print('playing end')
g1=gevent.spawn(eat)  # 开启一个协程
g2=gevent.spawn(play)
g1.join() # 主线程等待g1结束
g2.join()  # 主线程等待g2结束

 运行结果:

协程对time.sleep(1)不会有效果。只对gevent.sleep(1)有效果。除非用monkey模块。如下:

from gevent import monkey;monkey.patch_all()   # 有了这句代码,自动会把IO操作打包。否则就需要用gevent.sleep()
import gevent
def eat():
    print('eat:', threading.current_thread().getName()) #DummyThread-1假线程
    print('eating start')
    time.sleep(1) # IO事件
    print('eating end')
def play():
    print('play:', threading.current_thread().getName())
    print('playing start')
    time.sleep(1)  # IO事件
    print('playing end')
g1=gevent.spawn(eat)  # 开启一个协程
g2=gevent.spawn(play)
g1.join()
g2.join()

运行结果:

协程属于伪线程

6 同步和异步

# 进程和线程的状态切换是由操作系统完成
# 协程任务之间的切换是由程序(代码)完成。
    # 只有遇到协程模块能识别的IO操作的时候,程序才会进行任务切换,实现并发的效果

#同步和异步:在高IO之间使用协程操作
# 协程 : 能够在一个线程中实现并发效果的概念
    # 能够规避一些任务中的IO操作
    # 在任务的执行过程中检测到IO就切换到其他任务
from gevent import monkey;monkey.patch_all()  # 必须写在import其他模块之前
import time  
import gevent
def task():
    time.sleep(1)
    print(12345)
def sync():
    for i in range(10):
        task()
def async():
    g_lst=[]
    for i in range(10):
        g=gevent.spawn(task)
        g_lst.append(g)
    # for g in g_lst:g.join()
    gevent.joinall(g_lst)
sync()
async()

运行结果:

输出过程:先一秒一秒输出12345.输出四个后。同时输出5个12345

7 利用协程实现socket聊天

server模块:

import socket
from gevent import monkey;monkey.patch_all()
import gevent
def talk(conn):
    conn.send(b'hello')
    print(conn.recv(1024).decode('utf-8'))
    conn.close()
sk=socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
while True:
    conn,addr=sk.accept()
    gevent.spawn(talk,conn)
sk.close()

client模块:
 

import socket
sk=socket.socket()
sk.connect(('127.0.0.1',8080))
print(sk.recv(1024))
msg=input('>>>').encode('utf-8')
sk.send(msg)
sk.close()

运行结果:

进程,线程,协程个数关系

猜你喜欢

转载自blog.csdn.net/weixin_38383877/article/details/86093906