zoukankan      html  css  js  c++  java
  • Python程序中的线程操作-协程

    一、什么是协程

    协程: 就是单线程实现并发

    协程概念本质是程序员抽象出来的,是人为的控制通过程序的IO去进行切换任务的执行

    并发:任务切换+保存状态

    二、为什么要有协程

    自己控制切换要比操作系统切换快的多.降低了单个线程的io堵塞时间,也就是实现了单线程下效率最高.

    三、协程的优缺点

    • 优点:

      自己控制切换要比操作系统切换快的多

    • 缺点:

      1. 需要自己要检测所有的io,但凡有一个阻塞整体都跟着阻塞.
      2. 无法利用多核优势.

    四、如何实现协程

    其实协程的本质就是在单线程下实现并发,也就是通过生成器yieldnext进行迭代生成器,实现切换任务和保存任务。

    在Python中我们需要使用gevnet模块来实现协程

    五、Gevent模块

    Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet,它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

    5.1 模块的安装

    安装:pip3 install gevent

    5.2 用法介绍

    g1=gevent.spawn(func,1,,2,3,x=4,y=5):创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的

    g2=gevent.spawn(func2)
    

    g1.join():等待g1结束

    g2.join():等待g2结束

    上述两步合作一步:gevent.joinall([g1,g2])

    g1.value:拿到func1的返回值

    5.3 代码实例

    通过from gevent import monkey;

    monkey.patch_all()去补丁,捕获所以IO

    from gevent import monkey;monkey.patch_all()必须放到被打补丁者的前面,如time,socket模块之前。

    import time
    from gevent import monkey;monkey.patch_all()
    '''打了一个补丁,它可以实现捕获非gevent的所有io'''
    import gevent
    
    def eat():
        print('eat 1')
        time.sleep(2)
        # gevent.sleep(2)   # 可以这样单独捕捉阻塞,但是太麻烦,所以直接打补丁,捕捉运行期间的全部IO
        print('eat 2')
    def play():
        print('play 1')
        # 疯狂的计算呢没有io
        time.sleep(3)
        # gevent.sleep(3)   # 可以这样单独捕捉阻塞,但是太麻烦,所以直接打补丁,捕捉运行期间的全部IO
        print('play 2')
    
    '''
    gevent实现协程的模块,它可以捕获单线程中的io并去切换任务
    '''
    if __name__ == '__main__':
        # 把本该串行的代码通过协程完成单线程并行
        start = time.time()
        g1 = gevent.spawn(eat)      # 创建一个协程对象
        g2 = gevent.spawn(play)
        # g1.join() # 等待回收协程对象
        # g2.join()
        gevent.joinall([g1,g2])     # 把上面两步并一步
        end = time.time()
        print(end-start)
    

    六、gevent之应用

    通过gevent实现单线程下的socket并发

    注意:from gevent import monkey;monkey.patch_all()一定要放到导入socket模块之前,否则gevent无法识别socket的阻塞。

    服务器

    import socket
    from gevent import monkey; monkey.patch_all()   # 打补丁
    import gevent
    
    '''
    基于协程的socket通讯
    
    协程:单线程下实现并发
    '''
    
    def connec_interface(conn,addr):
        while 1:
            try:
                data = conn.recv(1024)
                if not data:
                    break
                print(f"来自{addr}的消息:",data.decode("utf8"))
                data = input(f"与{addr}聊天")
                conn.send(data.encode("utf8"))
            except:
                break
    
    
    if __name__ == '__main__':
        server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        server.bind(("127.0.0.1",8080))
        server.listen(5)
    
        while 1:
            print("等待连接。。。")
            conn,addr = server.accept()
            print("连接成功")
            gevent.spawn(connec_interface, conn, addr)  # 创建一个协程对象
    

    客户端

    import socket
    
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    client.connect(("127.0.0.1",8080))
    
    while 1:
        msg = input("请输入内容")
        client.send(msg.encode("utf8"))
        data = client.recv(1024)
        if not data:
            break
        print(data.decode("utf8"))
    
  • 相关阅读:
    求二叉树中最远两节点距离
    计算机系统
    webdriver高级应用- 无人工干预地自动下载某个文件
    webdriver高级应用- 改变一个页面对象的属性值
    webdriver高级应用- 在ajax方式产生的浮动框中,单击选择包含某个关键字的选项
    webdriver高级应用-js操作滚动条
    webdriver高级应用-使用JavaScript操作页面元素
    Selenium WebDriver- 指定页面加载时间
    Selenium WebDriver- 操作浏览器的cookie
    Selenium WebDriver- 操作JavaScript的prompt弹窗(使用率低)
  • 原文地址:https://www.cnblogs.com/XuChengNotes/p/11553360.html
Copyright © 2011-2022 走看看