• 14 并发编程-(协程)-greenlet模块&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()

     

  • 相关阅读:
    grep在指定类型的文件中查找字符 (转载)
    关于 android 中 postDelayed方法的讲解 (转载)
    linux下sprintf_s函数的替代(转载)
    两分钟彻底让你明白Android Activity生命周期(图文)!(转载)
    linux C之access函数(转载)
    Android.mk中call all-subdir-makefiles和call all-makefiles-under,$(LOCAL_PATH)的区别(转载)
    adb logcat 查看日志 (转载)
    Android 实用技巧 --- 命令godir (转载)
    emacs版本差异(转载)
    vim的visual可视模式(转载)
  • 原文地址:https://www.cnblogs.com/foremostxl/p/9737176.html
Copyright © 2020-2023  润新知