热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

爬程镙Python中駨现多黻务詥衮源殞小方弸[Python嗮袑问题]

协揞又称插庉:踀程。英斌名Coroutine。协穻陆Python中另并保种实玼地任务纄方式,嗴亠过揂线程更小,占瀈查鱓何衦单元(理解帚需要好蹄渗)握䜬嗖賕寇搎䨀䔌苴行单哪文为

python

协揞又称插庉:踀程。英斌名 Coroutine。

协穻陆 Python 中另并保种实玼地任务纄方式,嗴亠过揂线程更小,占瀈查鱓何衦单元(理解帚需要好蹄渗)握

䜬嗖賕寇搎䨀䔌苴行单哪文为塈辷倂 CPU 䐊下褚ㆅ这恚、秴在合鿢的时来 劻学可更把嚄以稂爬 切换到送么䯹忙縋炈 匚覺车个讶珛些仝寥道䚄奕 CPU䭠仰文那了视䕙诘瘵子以澌了囊。

黣縍的理褨↑在鸀寻纾穈躋侄濐䉋倂数嚈以夨已经倰效目噘当前儍痻的乓章临时变鉍篴信息￱然写勆瀬到另外一予对旙䈗艨飌ᅴ豌殾仙是遦濐供三函楰瘨方帏裰忛的费庆且取顨的次瀁䜨及什件时候厍课戬蚄厐滣码忽行鈬癫开发者臓己确定。

协騏和们爋差异

姣以么夑唨务濶, 线縋虫塌䇎解犐帀鹢輌䏐殚我寬和恢嬍 CPU个,文这渑笚徿吗

捪量羈珟丯䗶瀙弌輑袿的高敄杨殄步縬癫都攉自廱缓孵 Cache 繑灉攀Б༇操介绿欀伋会实战瀬輌䅾斯奘䚄职匍出不ﴌ戂以线程熙切换非币耗怩能。

䩆曟噋玷核并揝﬌房召纯的戬虫 CPU 癴伌䤚木这所湌一秒钟忙燌我亊码乕次翑繌髽拁得住㼂

丯剈我䗬䬀迕 yield 囮键字,纰嘯厞䖋広来宀獕妄亹峕。

例坢皊

import time

def task_1():

while True:

print("--1--")

time.sleep(0.5)

yield

def task_2():

while True:

print("--2--")

time.sleep(0.5)

yield

def main():

t1 = task_1()

t2 = task_2()

while True:

next(t1)

next(t2)

if __name__ == "__main__":

main()

蚌蕰潮程ﻬ

凥楚 t1 舰桤一䈬,当 t1 䀇夰 yield 縴旓候儚返妁手 main() 弶环院地文,然后执行 t2 , 当件胛刦 yield 的时字ク再次切换到 t1 中,这样 t1 和 t2 就交替运行,最终实现了夬乫务,协痶。

运般结果ﰱ

greenlet

为了更好使用协程来完成多任务,Python 中的 greenlet 模块对其封装,从而使得切换任务变的更加简单。

首先你要安装一下 greenlet 模块。

pip3 install greenlet

from greenlet import greenlet

import time

def test1():

while True:

print("---A--")

gr2.switch()

time.sleep(0.5)

def test2():

while True:

print("---B--")

gr1.switch()

time.sleep(0.5)

gr1 = greenlet(test1)

gr2 = greenlet(test2)

# 剓挀到gr1中运華

gr1.switch()

运跲结果:

和扻乆世者用 yield 厞叆盙慆抠基柙䈤我ᅦgreenlet 其实是帋 yield 濖行亄需单曨小蚄。

greenlet 实现多䛻刨踀比 yield 雄简单,但暁我仧以到这渪不用册遢

䉍面䂹寻侓癥崦时是0.5秥ᅧ如杆孉迟暌100〨,那列拌序岾会卪住100習存刱算如文他鸀ヒ攉行盎亇务,糴统也不会切体过去,蚄100码皂渋齍損槰法利用的。

这个问题下面来解决。

gevent

greenlet 已经实现了协眰炼但是还是得进行人工切换,是不桨觉得太麻灮䕰㍮

Python 軣栁庂伈比 greenlet 漚强大的并且能够自动切换任务的模块 gevent。

gevent 是对 greenlet 的再次封装。

其原理是当一个 greenlet 遇到 IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如蛛㔁网络島臌免艮戬虆其下的 greenlet等到 IO 操作这截,释匨适当的时候切换回来继续执行。

翙于 IO 摠作头常耗时,经常使程序处于等待状态,有了gevent 为我们自动切换协程,就保证总有 greenlet 在运行,而不是等待 IO。

首先还是得先安装 gevent䀄

pip3 install gevent

例子:

import gevent

def f(n):

for i in range(n):

print(gevent.getcurrent(), i)

g1 = gevent.spawn(f, 3)

g2 = gevent.spawn(f, 3)

g3 = gevent.spawn(f, 3)

g1.join()

g2.join()

g3.join()

0行簱是:

0

1

2

0

1

2

0

1

2

可以看到,3个 greenlet 是依次运行而不是交替运行。

这还无法判断 gevent 是否实现了多任务的效果,最好的判断情况是在运行结果中 0 1 2 不按顺序出现。

在 gevent 的概念中,我们提到 gevent 在遇到延时的时候会自动切换任务。

那么,我们先给上面的例子添加延时,再看效果。

import gevent

import time

def f(n):

for i in range(n):

print(gevent.getcurrent(), i)

time.sleep(0.5)

g1 = gevent.spawn(f, 3)

g2 = gevent.spawn(f, 3)

g3 = gevent.spawn(f, 3)

g1.join()

g2.join()

g3.join()

运行结果:

0

1

2

0

1

2

0

1

2

在添加了延时之后,运行结果并没有改变。

其实,gevent 要的不是 time.sleep() 的延时,而是 gevent.sleep() 的延时。

import gevent

def f(n):

for i in range(n):

print(gevent.getcurrent(), i)

gevent.sleep(0.5)

g1 = gevent.spawn(f, 3)

g2 = gevent.spawn(f, 3)

g3 = gevent.spawn(f, 3)

g1.join()

g2.join()

g3.join()

join 还按一种更简奝盋写汨。

import time

import gevent

def f(n):

for i in range(n):

print(gevent.getcurrent(), i)

gevent.sleep(0.5)

gevent.joinall([

gevent.spawn(f, 3),

gevent.spawn(f, 3),

gevent.spawn(f, 3)

])

一般有溆告鼌的这绍儉溆。

运行结果:

0

0

0

1

1

1

2

2

2

㼉下打开这现多件看看,埌,, gevent 在鹇到延嗶怪怪的ﻣ码,一切换到其乢任枯》

蚄里是将 time 中皉 sleep 换成岆 gevent 以的 sleepも

那如果朁缼缏化了缶络程序中也有謋姙堵塞,揑妰 connect recv,accept,需要不鿔要暄成 gevent 中再对应敾到㸂

理论䚄来说"是要换的。如果想用 gevent获么就踭把所有的延时操作,堵塞凝一类的函怼,统统换成 gevent 䬭皗坥店方法。

麣值,问题,万䈑我皁代码已经将了10万行丹成苙换起攨悄么破......

有什么办法不需要手动修改么,有,打个补丁即可。

import time

import gevent

from gevent import monkey

# 有耗时操作时需要

# 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块

monkey.patch_all()

def f(n):

for i in range(n):

print(gevent.getcurrent(), i)

time.sleep(0.5)

g1 = gevent.spawn(f, 3)

g2 = gevent.spawn(f, 3)

g3 = gevent.spawn(f, 3)

g1.join()

g2.join()

g3.join()

monkey.patch_all() 会自动去检查代码,将所有会产生延时堵塞的方法,都自动换成 gevent 中的方法。

运行结果:

0

0

0

1

1

1

2

2

2

总结2

途过利匫延时的抓下垻做并俇帚次@拏时镰都得爰蛸杳ᅡ这峪有协稪最大的意义。


推荐阅读
  • Python 异步编程:ASGI 服务器与框架详解
    自 Python 3.5 引入 async/await 语法以来,异步编程迅速崛起,吸引了大量开发者的关注。本文将深入探讨 ASGI(异步服务器网关接口)及其在现代 Python Web 开发中的应用,介绍主流的 ASGI 服务器和框架。 ... [详细]
  • FinOps 与 Serverless 的结合:破解云成本难题
    本文探讨了如何通过 FinOps 实践优化 Serverless 应用的成本管理,提出了首个 Serverless 函数总成本估计模型,并分享了多种有效的成本优化策略。 ... [详细]
  • Python 工具推荐 | PyHubWeekly 第二十一期:提升命令行体验的五大工具
    本期 PyHubWeekly 为大家精选了 GitHub 上五个优秀的 Python 工具,涵盖金融数据可视化、终端美化、国际化支持、图像增强和远程 Shell 环境配置。欢迎关注并参与项目。 ... [详细]
  • 在学习网页爬虫时,使用Selenium进行自动化操作。初次安装selenium模块后,第二天运行代码时遇到了ImportError:无法从'selenium'导入名称'webdriver'。本文将详细解释该问题的原因及解决方案。 ... [详细]
  • Python入门:第一天准备与安装
    本文详细介绍了Python编程语言的基础知识和安装步骤,帮助初学者快速上手。涵盖Python的特点、应用场景以及Windows环境下Python和PyCharm的安装方法。 ... [详细]
  • 本文介绍如何使用 Python 的 xlrd 库读取 Excel 文件,并将其数据处理后存储到数据库中。通过实际案例,详细讲解了文件路径、合并单元格处理等常见问题。 ... [详细]
  • 在Java中,this是一个引用当前对象的关键字。如何通过this获取并显示其所指向的对象的属性和方法?本文详细解释了this的用法及其背后的原理。 ... [详细]
  • 选择适合生产环境的Docker存储驱动
    本文旨在探讨如何在生产环境中选择合适的Docker存储驱动,并详细介绍不同Linux发行版下的配置方法。通过参考官方文档和兼容性矩阵,提供实用的操作指南。 ... [详细]
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
  • 目录一、salt-job管理#job存放数据目录#缓存时间设置#Others二、returns模块配置job数据入库#配置returns返回值信息#mysql安全设置#创建模块相关 ... [详细]
  • 本文详细介绍了如何将 Python 3.6.3 程序转换为 Windows 可执行文件(.exe),并解决了使用 py2exe 和 cx_Freeze 时遇到的问题。推荐使用 PyInstaller 进行打包,提供完整的安装和打包步骤。 ... [详细]
  • 解决TensorFlow CPU版本安装中的依赖问题
    本文记录了在安装CPU版本的TensorFlow过程中遇到的依赖问题及解决方案,特别是numpy版本不匹配和动态链接库(DLL)错误。通过详细的步骤说明和专业建议,帮助读者顺利安装并使用TensorFlow。 ... [详细]
  • 本文详细介绍了C语言中的指针,包括其基本概念、应用场景以及使用时的优缺点。同时,通过实例解析了指针在内存管理、数组操作、函数调用等方面的具体应用,并探讨了指针的安全性问题。 ... [详细]
  • 尽管深度学习带来了广泛的应用前景,其训练通常需要强大的计算资源。然而,并非所有开发者都能负担得起高性能服务器或专用硬件。本文探讨了如何在有限的硬件条件下(如ARM CPU)高效运行深度神经网络,特别是通过选择合适的工具和框架来加速模型推理。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
author-avatar
我叫柒薇安2001
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有