123 Python程序中的线程操作-协程

系统 1481 0

目录

  • 一、什么是协程
  • 二、为什么要有协程
  • 三、协程的优缺点
  • 四、如何实现协程
  • 五、Gevent模块
    • 5.1 模块的安装
    • 5.2 用法介绍
    • 5.3 代码实例
  • 六、gevent之应用

一、什么是协程

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

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

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

二、为什么要有协程

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

三、协程的优缺点

  • 优点:

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

  • 缺点:

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

四、如何实现协程

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

在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"))
          
        

更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论