14 并发编程-(协程)-greenlet模块&gevent模块

本文深入探讨了greenlet和gevent模块在Python中实现多任务切换及并发编程的方法。通过对比yield,greenlet提供了更简单的多任务切换方案,而gevent则通过检测I/O操作自动切换任务,利用Greenlet模式实现并发或异步编程,尤其是在识别gevent可识别的阻塞方面。文章还介绍了基于gevent模块实现并发套接字通信的具体实例。

 

1、实现多个任务之间进行切换,yield、greenlet都没有实现检测I/O,greenlet在实现多任务切换下更简单

from greenlet import greenlet
def eat(name):
    print(f"{name} eat 1")
    g2.switch('egon') # 切换
    print(f"{name} eat 2")
    g2.switch()
def play(name):
    print(f"{name} play 1")
    g1.switch()
    print(f"{name} play 2")
g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch('egon') # 程序从此处执行

egon eat 1
egon play 1
egon eat 2
egon play 2

 

2、一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))

2.1 gevent模块

可以轻松的实现并发或异步编程,在gevent中用到的主要模式是Greenlet,

2.1.1、遇到io阻塞时会自动切换任务 --只实现识别gevent可以识别的阻塞

# 遇到io阻塞会自动切换任务
import gevent,time
def eat(name):
    print(f"{name} eat1")
    gevent.sleep(2)  # 模拟io阻塞
    print(f"{name} eat2")
def play(name):
    print(f"{name} play1")
    gevent.sleep(2)
    print(f"{name} play2")
start = time.time()
g1 = gevent.spawn(eat,'alex')
g2 = gevent.spawn(play,'alex')
g1.join()
g2.join()
stop = time.time()
print(stop-start)

alex eat1
alex play1
alex eat2
alex play2
2.007000207901001

2.1.2、实际情况中的应用gevent  打补丁(monkey.patch_all()) 识别 所有阻塞

 

 

alex eat1
alex play1
alex eat2
alex play2
2.005999803543091

3、基于gvent模块实现并发的套接字通信

服务端:

# 基于 gevent
from gevent import monkey;monkey.patch_all()
import socket
import gevent

def Server(ip_port):
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.bind(ip_port)
    server.listen(5)
    while True:
        conn,addr = server.accept()
        gevent.spawn(communicate,conn)
    server.close()
def communicate(conn):
    while True:
        try:
            data = conn.recv(1024).decode('utf-8')
            conn.send(data.upper().encode('utf-8'))
        except Exception as e:
            print(e)
            break
    conn.close()
if __name__ == '__main__':
    ip_port = ('127.0.0.1',8080)
    Server(ip_port)
    # g = gevent.spawn(Server,ip_port)
    # g.join()

客户端:启动500个线程模拟500个客户端向服务端发消息

import socket
from threading import Thread,currentThread
def client():
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    ip_port = ('127.0.0.1',8080)
    client.connect(ip_port)
    while True:
        client.send(f"{currentThread().getName()} hello".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()

 

 

 

转载于:https://www.cnblogs.com/foremostxl/p/9737176.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值