首页 > 编程语言 >Python多任务协程:编写高性能应用的秘密武器

Python多任务协程:编写高性能应用的秘密武器

时间:2024-01-24 17:06:21浏览次数:37  
标签:spawn task 协程 Python gevent 线程 多任务

Python多任务协程:编写高性能应用的秘密武器_测试管理


多任务协程编程

协程,又称微线程,纤程。英文名Coroutine。

协程也是一种轻量级的多任务编程技术,它可以在同一个线程中实现多个任务的切换和调度。

协程通过任务的暂停和恢复,避免了线程切换的开销并减少了锁的使用。协程常用于异步编程场景,比如网络编程和IO密集型任务。

最大的优势就是协程极高的执行效率。因为函数切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

比如:一个人在打印资料的等待过程中,又去接听了客户的电话,在接听电话的等待过程中,又整理了桌面。

Python 中可以使用第三方模块 gevent 实现进程多任务编程。

# pip install gevent
import gevent

创建协程

gevent 模块使用 spawn 类创建协程实例对象,实现协程任务的创建。

spawn(run [, args [, kwargs]])

参数说明:

  • run:执行的目标任务名
  • args:以元组方式给执行任务传参
  • kwargs:以字典方式给执行任务传参
import gevent

def task():
    for i in range(1,3):
        print(i)

g1 = gevent.spawn(task)
g2 = gevent.spawn(task)
g3 = gevent.spawn(task)

启动进程

协程对象创建成功后,需要使用 join() 方法启动协程才会开始执行。

该方法的作用是对当前线程进行阻塞,直到协程执行结束后,继续执行当前线程。

g1.join()
g2.join()
g3.join()
print("main")

获取当前协程对象

gevent.getcurrent() 可以获取当前协程对象。

import gevent

def task():
    for i in range(1,3):
        print(gevent.getcurrent(), i)

g1 = gevent.spawn(task)
g2 = gevent.spawn(task)
g1.join()
g2.join()

协程组

在创建多个协程对象后,可以将多个协程对象放入一个元组或列表中,然后使用 gevent.joinall() 方法同时启动协程对象。

import gevent

def task():
    for i in range(1,3):
        print(gevent.getcurrent(), i)


# 使用列表推导式,生成一个有5个协程对象的列表
gs = [gevent.spawn(task) for i in range(5)]
gevent.joinall(gs)

协程切换

从前面的代码执行结果看,虽然可以执行多个协程任务,但是任务的执行过程依然是同步的。

可以通过在代码中添加 gevent.sleep() 方法模拟耗时操作,实现协程任务的切换。

注意: sleep() 方法是 gevent 模块中的,不是 time 模块中的。

import gevent

def task():
    for i in range(1,3):
        print(gevent.getcurrent(), i)
        gevent.sleep(0.001)

# 使用列表推导式,生成一个有5个协程对象的列表
gs = [gevent.spawn(task) for i in range(5)]
gevent.joinall(gs)

协程任务函数传参

在创建协程对象的时候,为协程任务函数传递参数,可以使用两种方式为任务函数传参。

  • args: 使用可变位置参数形式传参
  • kwargs: 使用可变关键字参数形式传参

协程的任务函数传参与进程和线程不同,协程可以和直接使用函数一样,在 spawn 方法中为任务函数传参。

import gevent

def task(n, msg):
    for i in range(1,n+1):
        print(gevent.getcurrent(), f"第 {i} 次输出 {msg}")
        gevent.sleep(0.001)

g1 = gevent.spawn(task,5, "Python")
g2 = gevent.spawn(task, msg="Hogwarts", n=5)
g1.join()
g2.join()

协程异步

在 Python 中,Gevent 的 monkey patch 是指使用 Gevent 的模块 gevent.monkey 中的 patch_all() 等方法,来替换标准库中的一些阻塞式 I/O 操作,以实现非阻塞式的协程 I/O。

一般该方法写在程序的第一行。

from gevent import monkey
monkey.patch_all()
import gevent
import random


def task(n, msg):
    for i in range(1,n+1):
        print(gevent.getcurrent(), f"第 {i} 次输出 {msg}")
        gevent.sleep(random.random())


g1 = gevent.spawn(task,5, "Python")
g2 = gevent.spawn(task, msg="Hogwarts", n=5)
g3 = gevent.spawn(task, n=5, msg="Hello")
gevent.joinall((g1,g2,g3))

在 Python 3.10 版本中,Gevent 的 monkey patch 功能在某些情况下可能无效。这是因为在 Python 3.10 中引入了 asyncio 的新的事件循环机制,与 Gevent 的事件循环有所不同,导致 monkey patch 在有些情况下失效。

Gevent 官方还没有正式发布兼容 Python 3.10 版本的版本,因此在 Python 3.10 中使用 monkey.patch_all() 方法可能无法正常实现非阻塞的协程 I/O。

为了解决这个问题,你可以考虑使用 Python 3.10 引入的 asyncio 模块来进行异步编程。

asyncio 提供了原生的协程和事件循环,可以实现高效的异步操作。

标签:spawn,task,协程,Python,gevent,线程,多任务
From: https://blog.51cto.com/u_15640304/9399907

相关文章

  • 用Python实现高效数据记录!Web自动化技术助你告别重复劳动!
    简介关键数据记录是Web自动化测试中的关键部分,它们提供了关于系统行为和执行过程的详细信息,有助于验证用例的正确性,排查问题和确保应用程序的质量。行为日志行为日志是一种用于记录系统或应用程序的操作和事件的技术。它的目的是为了跟踪和记录应用程序的执行过程,以便在需要时审......
  • Python - “人生苦短,我用Python”
      字符串的三种定义方式1、单引号定义法:name='人生苦短,我用Python'2、双引号定义法:name="人生苦短,我用Python"3、三引号定义法:name="""人生苦短,我用Python"""三引号定义法,和多行注释的写法一样,同样支持换行操作。使用变量接收它,它就是字符串;不使用变量接收它,就......
  • Python并发编程之进程间通信与线程间通信
    进程间通信与线程间通信【一】进程间通信(IPC)​ 进程间通信(Inter-ProcessCommunication,IPC)是指在不同进程之间进行数据交换和信息传递的机制。在多进程系统中,不同进程可能运行在不同的地址空间,因此需要一些特殊的方法来实现它们之间的通信。以下是一些常见的进程间通信的方法:......
  • python创建json文件并换行
     在Python中,您可以使用内置的json 模块创建和操作JSON文件。以下是如何创建一个JSON文件的步骤:1、Json格式JSON数据的书写格式是键(名称)/值对。JSON值可以是:字符串(在双引号中)、数组(在中括号中)、数字(整数或浮点数)、逻辑值(true或false)、对象(在大括号中)、null。JSON......
  • 使用Python生成模拟数据的方法
     在数据分析和机器学习领域,生成模拟数据是非常重要的一步。Python作为一种流行的编程语言,提供了多种方法来生成模拟数据。本文将介绍一些常用的Python库和技术,帮助你了解如何使用Python生成模拟数据。 一、使用random库生成随机数 Python的random库提供了生成伪随机数的函数,可......
  • Python学习笔记
    一、第一个Python程序1.1软件安装Anaconda:管理不同开发环境(如python3解释器),及它们的各种库(如numpy库)PyCharm:集成开发环境(IDE)1.2HelloWorld打开PyCharm→新建项目→选择项目保存位置、先前配置的环境(方法见Anaconda使用笔记)......
  • Python(2) -numpy 的常规函数
    1、tile参考:https://blog.csdn.net/weixin_41998772/article/details/113563806用法tile(A,reps)tile是平铺的意思。即将数组A是为瓷砖,在一个二维平面reps平铺开来0、给定一个数组fromnumpyimport*c=array([[1,2],[3,4]])print(c)Output:[[12][34]]1、横向平......
  • (保姆级)服务器-Zabbix6.0使用Python脚本实现带图片的邮箱的报警
    前言近期在琢磨Zabbix邮箱报警的功能,但是网上的教程通常是4.0或5.0版本Zabbix,并使用Python2.7环境,运行在新版本Zabbix6.0上有颇多问题,为此我基于原先教程修改基于Zabbix6.0并使用Python3+的解决方案。期间遇到不少坑,特此分享。Zabbix自带报警Zabbix是自带的邮箱的报警功能有限......
  • python----处理exl表格,将其转换成其他代码的方法
    用python获取表格数据的基本方法如下:值得注意的是,在后续学习中发现对单个数据做sheet得到的是单个cell类型数据,对多个做sheet处理得到的是多个cell组成的元组,要想把这些cell的值合并得先分别提取出cell的值再合并成新的list,不知道是否有更简单的方法。如何用利用得到的表格数据......
  • python多线程id获取
    demoimportthreadingimporttimedefprint_thread_info(thread_name):"""线程函数,打印线程名称和ID以及一些文本"""foriinrange(3):time.sleep(1)thread_id=threading.current_thread().identprint(f"{thr......