【Python并发编程】协程篇

【Python并发编程】协程篇

什么是协程?

  • 使用单线程 从程序的角度去实现并发执行
  • 协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

目录

协程模块

0x01:greenlet模块

    • 如果我们在单个线程内有 20 个任务,要想实现在多个任务之间切换,使用yield生成器的方式过于麻烦(需要先得到初始化一次的生成器,然后再调用 send。。。非常麻烦),而使用 greenlet 模块可以非常简单地实现这20个任务直接的切换
    • 由于 greenlet 模块不能实现自动检测IO操作,所以这里我们重点讲 gevent 模块

0x02:gevent模块

  • 异步执行任务,自动检测IO操作,自动切换

  • gevent 中用到的主要模式是 Greenlet, 它是以C扩展模块形式接入 Python 的轻量级协程。

    • Greenlet 全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
  • 例 :结合 gevent 模块下的子模块 monkey,实现自动检测代码中的IO操作,并且自动切换 gevent 定义的任务

from gevent import monkey;monkey.patch_all()
import gevent
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(4)
        print('%s play 2' % name)

        start = time.time()
        g1=gevent.spawn(eat, 'egon')    # 将函数添加到gevent任务列表
        g2=gevent.spawn(play, 'alex')

        # g1.join()
        # g2.join()
        gevent.joinall([g1, g2])    # 代替单个join操作
        stop = time.time()
        print(stop-start)
        
start = time.time()
g1=gevent.spawn(eat, 'egon')    # 将函数添加到gevent任务列表
g2=gevent.spawn(play, 'alex')

# g1.join()
# g2.join()

gevent.joinall([g1, g2])    # 代替单个join操作
stop = time.time()
print(stop-start)

运行结果

egon eat 1
alex play 1
egon eat 2
alex play 2
4.006288051605225

0x03:单线程下实现并发socket通讯

服务端代码

#基于gevent实现
from gevent import monkey,spawn;monkey.patch_all()
from socket import *
def communicate(conn):
    while True:
        try:
            data=conn.recv(1024)
            if not data:break
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
def server(ip,port):
    server = socket(AF_INET, SOCK_STREAM)
    server.bind((ip,port))
    server.listen(5)
    while True:
        conn, addr = server.accept()
        spawn(communicate,conn)
    server.close()
if __name__ == '__main__':
    g=spawn(server,'127.0.0.1',8090)
    g.join()

客户端代码

from socket import *
from threading import Thread,currentThread
def client():
    client=socket(AF_INET,SOCK_STREAM)
    client.connect(('127.0.0.1',8090))
    while True:
        client.send(('%s hello' %currentThread().getName()).encode('utf-8'))
        data=client.recv(1024)
        print(data.decode('utf-8'))
    client.close()
if __name__ == '__main__':
    for i in range(500):
        t=Thread(target=client)
        t.start()

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://codeyee.com/archives/python-gevent.html