1.Python 协程 asyncio模块底层原理详解
2.python中的协程协程asyncio使用详解与异步协程的处理流程分析
3.Python程序开发系列并发执行协程任务超时的解决方案(案例分析)
4.å¨Pythonä¸ä½¿ç¨Asyncioç³»ç»ï¼3-4ï¼Task å Future
5.å¦ä½ç¨pythonåä¸ä¸ªåç¨
6.python协程(4):asyncio
Python 协程 asyncio模块底层原理详解
coroutine function
定义于async def的function,其执行并不立即启动,而是返回一个coroutine object.
运行coroutine function需切换至async模式,使event loop启动.此过程将coroutine object转化为task.
通过asyncio.run(coroutine object)实现.
多 task
任务在event loop中以task形式执行.使用await提交多个任务.
调用coroutine function返回coroutine object,await操作实质是提交一个coroutine object.
事件循环主动将控制权交予可执行的task,task通过await或执行完毕交还控制权.
若任务间存在死循环,事件循环会因控制权交接受阻而停滞.
程序执行时间受任务顺序影响.多个sleep任务依次执行.
并发多 task
await task2是否加入取决于任务是否需要返回值.若有多个任务且需要返回值,使用asyncio.gather()实现.
asyncio.gather()接收coroutine object、task、源码future object,协程协程处理后提交至事件循环,返回顺序列表.
总结
定义coroutine function为async def xx().
通过调用自身xx()生成coroutine object.
await、asyncio.create_task()、源码asyncio.gather()用于提交任务至事件循环.
asyncio.run(xx())启动事件循环执行任务.
并发执行中,协程协程任务间等待时间被有效利用,但本质上仍是顺序执行.
python中的asyncio使用详解与异步协程的处理流程分析
一些核心概念
异步函数的定义
普通函数通过使用 def 关键词定义,而异步函数,源码末日争霸源码即协程函数 (Coroutine) 是协程协程一种特殊类型的函数,可以在代码块中将执行权交予其他协程。源码定义时使用 async def 关键词。协程协程
如何调用协程并获得结果
调用普通函数如 result = add2(2) 可直接运行并返回结果4。源码然而,协程协程调用 result = add3(2) 会返回一个协程对象,源码而非结果2+3=5。协程协程nginx源码修改要获得结果,源码需将协程放置于事件循环中执行。协程协程
事件循环 Eventloop
Eventloop 是 asyncio 应用的核心,它注册并循环执行异步函数。在执行过程中,遇到需要等待的 I/O 操作(如网络请求)时会暂停执行,切换到其他函数。这使得多个异步函数可以协同运行。
得到协程执行结果
要得到协程函数的结果,必须先创建一个 Eventloop 或者在调用协程时使用 await 关键字。例如,result = await add3(2)。图形算法源码await 只能在协程函数中使用。
复杂协程执行示例
通过将两个协程放在 main 函数中,事件循环会按顺序执行它们,即便两个协程内部有不同等待时间。要使协程并行执行,需要使用 asyncio.gather() 函数。
使用 asyncio.gather() 和 Task 任务对象
通过 asyncio.gather() 可以并行执行多个协程函数,返回结果是一个列表。使用 Task 对象如 asyncio.ensure_future() 或 loop.create_task() 可动态添加协程到事件循环。
异步函数与同步函数的执行
创建 task 对象并使用 loop.run_until_complete() 可以运行协程函数。同时,可以为 task 对象添加回调方法,android源码邮箱当协程执行结束时调用事件循环的 stop 方法来结束整个循环。
并行执行多个协程
使用 asyncio.gather() 函数可以轻松并行执行多个协程,并通过调用 await asyncio.gather(*) 获取所有结果。
异步与多线程的结合
在事件循环中动态添加同步函数可以通过子线程运行事件循环并使用 loop.call_soon_threadsafe() 方法添加函数。为了实现并发执行,可以使用 run_in_executor() 方法在执行器中执行同步函数。
执行器的选择
使用 concurrent.futures 下的 ThreadPoolExecutor 或 ProcessPoolExecutor 可在多线程或多进程中执行同步函数。注意它们在初始化时的 max_workers 参数决定执行器的工作线程数。
异步函数的动态添加
使用 asyncio.run_coroutine_threadsafe() 可以将协程绑定到事件循环上,避免阻塞主线程。通过 gather() 方法结合 run_coroutine_threadsafe() 和 run_in_executor() 获得多个协程的结果。
获取协程结果
使用 asyncio.gather() 可以并行获取多个协程的eclipse汉化源码结果。注意,获取结果时协程所在的线程与主线程可能不同,这取决于事件循环的运行方式。
异步库与实践
总结了异步协程的基本概念与流程后,接下来可以进一步学习与实践如 aioplete()ãè¿åä½ ä»¥åè§è¿çä¸ä¸æ ·ãç°å¨å¾ªç¯æ£å¨è¿è¡ï¼main()åç¨å°å¼å§æ§è¡.
ï¼Lï¼æç»ï¼å½futureçç»æ被设置æ¶ï¼å®å°±å®æäºãå®æåï¼å¯ä»¥è®¿é®ç»æã
å½ç¶ï¼ä½ ä¸å¤ªå¯è½ä»¥è¿éæ示çæ¹å¼ç´æ¥ä½¿ç¨Futureï¼ä»£ç 示ä¾ä» ç¨äºæè²ç®çãä½ ä¸asynccioç大é¨åèç³»é½æ¯éè¿Taskå®ä¾è¿è¡çã
ä½ å¯è½æ³ç¥éå¦æå¨Taskå®ä¾ä¸è°ç¨set_result()ä¼åçä»ä¹ãå¨Python 3.8ä¹åå¯ä»¥è¿æ ·åï¼ä½ç°å¨ä¸å 许è¿ä¹åäºãä»»å¡å®ä¾æ¯åç¨å¯¹è±¡çå è£ å¨ï¼å®ä»¬çç»æå¼åªè½å¨å é¨è®¾ç½®ä¸ºåºå±åç¨å½æ°çç»æï¼å¦ ç¤ºä¾ 3-æ示é£æ ·ã
ç¤ºä¾ 3-. å¨taskä¸è°ç¨set_result
ï¼Lï¼å¯ä¸çåºå«æ¯æ们å建çæ¯Taskå®ä¾èä¸æ¯Futureå®ä¾ãå½ç¶ï¼Task APIè¦æ±æ们æä¾ä¸ä¸ªåç¨ï¼è¿éæ们使ç¨sleep()åªæ¯å 为ç®åæ¹ä¾¿ã
ï¼L7ï¼æ£å¨ä¼ å ¥ä¸ä¸ªTaskå®ä¾ãå®æ»¡è¶³å½æ°çç±»åç¾å(å 为Taskæ¯Futureçåç±»)ï¼ä½ä»Python 3.8å¼å§ï¼æ们ä¸åå 许å¨Taskä¸è°ç¨set_result()ï¼å°è¯è¿æ ·åå°å¼åRuntimeErrorãè¿ä¸ªæ³æ³æ¯ï¼ä¸ä¸ªTask代表ä¸ä¸ªæ£å¨è¿è¡çåç¨ï¼æ以ç»æåºè¯¥æ»æ¯æ¥èªäºtaskèªèº«ã
ï¼L, Lï¼ä½æ¯ï¼æ们ä»ç¶å¯ä»¥cancel()ä¸ä¸ªä»»å¡ï¼å®å°å¨åºå±åç¨ä¸å¼åCancelledErrorã
Create_task? Ensure_Future? ä¸å®å³å¿å§ï¼
å¨ç¬¬é¡µçâå¿«éå ¥é¨âä¸ï¼æ说è¿è¿è¡åç¨çæ¹æ³æ¯ä½¿ç¨asyncio.create_task()ãå¨å¼å ¥è¯¥å½æ°ä¹åï¼æå¿ è¦è·åä¸ä¸ªå¾ªç¯å®ä¾å¹¶ä½¿ç¨loop.create_task()å®æç¸åçä»»å¡ãäºå®ä¸ï¼è¿ä¹å¯ä»¥éè¿ä¸ä¸ªä¸åç模å级å½æ°æ¥å®ç°:asyncio.ensure_future()ãä¸äºå¼å人åæ¨ècreate_task()ï¼èå ¶ä»äººæ¨èensure_future()ã
å¨æ为è¿æ¬ä¹¦åç 究çè¿ç¨ä¸ï¼æ确信APIæ¹æ³asyncio.ensure_future()æ¯å¼èµ·å¯¹asyncioåºå¹¿æ³è¯¯è§£ç罪é祸é¦ãAPIç大é¨åå 容é½éå¸¸æ¸ æ°ï¼ä½å¨å¦ä¹ è¿ç¨ä¸è¿åå¨ä¸äºä¸¥éçéç¢ï¼è¿å°±æ¯å ¶ä¸ä¹ä¸ãå½ä½ éå°ensure_future()æ¶ï¼ä½ ç大èä¼é常åªåå°å°å ¶éæå°å ³äºasyncioåºè¯¥å¦ä½ä½¿ç¨çå¿ç模åä¸ââä½å¾å¯è½ä¼å¤±è´¥!
å¨Python 3.6 asyncio ææ¡£ä¸ï¼è¿ä¸ªç°å¨å·²ç»èåæèç解éçªåºäº ensure_future() çé®é¢ï¼
asyncio.ensure_future(coro_or_future, *, _loop =None)
å®ææ§è¡ä¸ä¸ªåç¨å¯¹è±¡ï¼æå®å è£ å¨futureä¸ãè¿åä¸ä¸ªTask对象ãå¦æåæ°æ¯Futureï¼åç´æ¥è¿åã
ä»ä¹!? å½æ第ä¸æ¬¡è¯»å°è¿ç¯æç« æ¶ï¼æå¾å°æãä¸é¢å¸ææ¯å¯¹ensure_future()çæ´æ¸ æ¥çæè¿°:
è¿ä¸ªå½æ°å¾å¥½å°è¯´æäºé对ç»ç«¯ç¨æ·å¼å人åçasyncio API(é«çº§API)åé对æ¡æ¶è®¾è®¡äººåçasyncio API(ä½çº§API)ä¹é´çåºå«ã让æ们å¨ç¤ºä¾ 3-ä¸èªä¹ ççå®æ¯å¦ä½å·¥ä½çã
ç¤ºä¾ 3-. ä»ç»ççensure_future()å¨åä»ä¹
ï¼L3ï¼ä¸ä¸ªç®åçä»ä¹é½ä¸åçåç¨å½æ°ãæ们åªéè¦ä¸äºè½ç»æåç¨çä¸è¥¿ã
ï¼L6ï¼æ们éè¿ç´æ¥è°ç¨è¯¥å½æ°æ¥å建åç¨å¯¹è±¡ãä½ ç代ç å¾å°ä¼è¿æ ·åï¼ä½ææ³å¨è¿éæç¡®å°è¡¨ç¤ºï¼æ们æ£å¨åæ¯ä¸ªcreate_task()åensure_future()ä¼ éä¸ä¸ªåç¨å¯¹è±¡ã
ï¼L7ï¼è·åä¸ä¸ªå¾ªç¯ã
ï¼L9ï¼é¦å ï¼æ们使ç¨loop.create_task()å¨å¾ªç¯ä¸è°åº¦åç¨ï¼å¹¶è¿åä¸ä¸ªæ°çTaskå®ä¾ã
ï¼Lï¼éªè¯ç±»åãå°ç®å为æ¢ï¼æ²¡æä»ä¹æ趣çã
ï¼Lï¼æ们å±ç¤ºäºasyncio.ensure_future()å¯ä»¥è¢«ç¨æ¥æ§è¡ä¸create_task()ç¸åçå¨ä½ï¼æä»¬ä¼ å ¥äºä¸ä¸ªåç¨ï¼å¹¶è¿åäºä¸ä¸ªTaskå®ä¾(并ä¸åç¨å·²ç»è¢«å®æå¨å¾ªç¯ä¸è¿è¡)!å¦æä¼ å ¥çæ¯åç¨ï¼é£ä¹loop.create_task()åasyncio.ensure_future()ä¹é´æ²¡æåºå«ã
ï¼Lï¼å¦ææ们ç»ensure_future()ä¼ éä¸ä¸ªTaskå®ä¾ä¼åçä»ä¹å¢ï¼æ³¨ææ们è¦ä¼ éçTaskå®ä¾æ¯å·²ç»å¨ç¬¬4æ¥éè¿loop.create_task()å建好çã
ï¼Lï¼è¿åçTaskå®ä¾ä¸ä¼ å ¥çTaskå®ä¾å®å ¨ç¸å:å®å¨è¢«ä¼ éæ¶æ²¡æ被æ¹åã
ç´æ¥ä¼ éFutureå®ä¾çæä¹ä½å¨ï¼ä¸ºä»ä¹ç¨åä¸ä¸ªå½æ°å两件ä¸åçäºæ ï¼çæ¡æ¯ï¼ensure_future()çç®çæ¯è®©æ¡æ¶ä½è åæç»ç¨æ·å¼åè æä¾å¯ä»¥å¤ç两ç§åæ°çAPIãä¸ç¸ä¿¡æï¼è¿æ¯ex-BDFLèªå·±è¯´çï¼
ensure_future()çè¦ç¹æ¯ï¼å¦æä½ æä¸ä¸ªå¯è½æ¯åç¨æFuture(åè å æ¬ä¸ä¸ªTaskï¼å 为å®æ¯Futureçåç±»)çä¸è¥¿ï¼å¹¶ä¸ä½ æ³è½å¤è°ç¨ä¸ä¸ªåªå¨Futureä¸å®ä¹çæ¹æ³(å¯è½å¯ä¸æç¨çä¾åæ¯cancel())ãå½å®å·²ç»æ¯Future(æTask)æ¶ï¼å®ä»ä¹ä¹ä¸åï¼å½å®æ¯åç¨æ¶ï¼å®å°å®å è£ å¨Taskä¸ã
å¦ææ¨ç¥éæ¨æä¸ä¸ªåç¨ï¼å¹¶ä¸å¸æå®è¢«è°åº¦ï¼é£ä¹æ£ç¡®çAPIæ¯create_task()ãå¯ä¸åºè¯¥è°ç¨ensure_future()çæ¶åæ¯å½ä½ æä¾ä¸ä¸ªAPI(å大å¤æ°asyncioèªå·±çAPI)ï¼å®æ¥ååç¨æFutureï¼ä½ éè¦å¯¹å®åä¸äºäºæ ï¼éè¦ä½ æä¸ä¸ªFutureã
âGuido van Rossum
æ»èè¨ä¹ï¼asyncio.sure_future()æ¯ä¸ä¸ªä¸ºæ¡æ¶è®¾è®¡è åå¤çè¾ å©å½æ°ãè¿ä¸ç¹æ容æéè¿ä¸ä¸ç§æ´å¸¸è§çå½æ°è¿è¡ç±»æ¯æ¥è§£éï¼æ以æ们æ¥åè¿ä¸ªè§£éãå¦æä½ æå å¹´çç¼ç¨ç»éªï¼ä½ å¯è½å·²ç»è§è¿ç±»ä¼¼äºä¾3-ä¸çistify()å½æ°çå½æ°ãç¤ºä¾ 3-ä¸listify()çå½æ°ã
ç¤ºä¾ 3-. ä¸ä¸ªå¼ºå¶è¾å ¥å表çå·¥å ·å½æ°
è¿ä¸ªå½æ°è¯å¾å°åæ°è½¬æ¢ä¸ºä¸ä¸ªå表ï¼ä¸ç®¡è¾å ¥çæ¯ä»ä¹ãapiåæ¡æ¶ä¸ç»å¸¸ä½¿ç¨è¿ç±»å½æ°å°è¾å ¥å¼ºå¶è½¬æ¢ä¸ºå·²ç¥ç±»åï¼è¿å°ç®ååç»ä»£ç ââå¨æ¬ä¾ä¸ï¼æ¨ç¥éåæ°(æ¥èªlistify()çè¾åº)å°å§ç»æ¯ä¸ä¸ªå表ã
å¦ææå°listify()å½æ°éå½å为ensure_list()ï¼é£ä¹æ¨åºè¯¥å¼å§çå°ä¸asyncio.ensure_future()ç类似ä¹å¤:å®æ»æ¯è¯å¾å°åæ°å¼ºå¶è½¬æ¢ä¸ºFuture(æåç±»)ç±»åãè¿æ¯ä¸ä¸ªå®ç¨å½æ°ï¼å®ä½¿æ¡æ¶å¼å人å(èä¸æ¯åä½ æè¿æ ·çç»ç«¯ç¨æ·å¼å人å)çå·¥ä½åå¾æ´å®¹æã
å®é ä¸ï¼asyncioæ ååºæ¨¡åæ¬èº«ä½¿ç¨ensure_future()æ£æ¯åºäºè¿ä¸ªåå ãå½ä½ ä¸æ¬¡æ¥çAPIæ¶ï¼ä½ ä¼åç°å½æ°åæ°è¢«æ述为âå¯çå¾ å¯¹è±¡âï¼å¾å¯è½å é¨ä½¿ç¨ensure_future()强å¶è½¬æ¢åæ°ãä¾å¦ï¼asyncio.gather()å½æ°å°±åä¸é¢ç代ç ä¸æ ·:
awsåæ°è¡¨ç¤ºâå¯çå¾ å¯¹è±¡âï¼å æ¬åç¨ãtaskåfutureãå¨å é¨ï¼gather()使ç¨ensure_future()è¿è¡ç±»å强å¶è½¬æ¢ï¼taskåfutureä¿æä¸åï¼èæåç¨å¼ºå¶è½¬ä¸ºtaskã
è¿éçå ³é®æ¯ï¼ä½ä¸ºç»ç«¯ç¨æ·åºç¨ç¨åºå¼å人åï¼åºè¯¥æ°¸è¿ä¸éè¦ä½¿ç¨asyncio.ensure_future()ãå®æ´åæ¯æ¡æ¶è®¾è®¡å¸çå·¥å ·ãå¦æä½ éè¦å¨äºä»¶å¾ªç¯ä¸è°åº¦åç¨ï¼åªéç´æ¥ä½¿ç¨asyncio.create_task()æ¥å®æã
å¨æ¥ä¸æ¥çå èä¸ï¼æ们å°åå°è¯è¨çº§å«çç¹æ§ï¼ä»å¼æ¥ä¸ä¸æ管çå¨å¼å§ã
å¦ä½ç¨pythonåä¸ä¸ªåç¨
1 使ç¨çº¯Python代ç å¼å (å¿ é¡»æ¯äººå½¢ï¼éçéç«éå ¶ä»)ã
2 çæ£çæä½ç³»ç»ï¼ä¸ä» ä» è½è°åº¦ä»»å¡ï¼è¿æä¾äºè®¸è®¸å¤å¤çç³»ç»è°ç¨ï¼æ¯å¦è¯´æ°å»ºä¸ä¸ªè¿ç¨ï¼killä¸ä¸ªè¿ç¨ï¼è¿äºæ们ä¹è¦å®ç°ï¼ï¼(æ以说就ç®æ¯æ¾ä¸ªå æ°çä¹å¿ é¡»æ¯æå¤åè½ç)
3 å¯ä»¥å¤çå¤ä»»å¡ (æ´è¡£åé¥å¥é½è½å¹²)ï¼
python协程(4):asyncio
asyncio是官方提供的协程的类库,从python3.4开始支持该模块async & awiat是python3.5中引入的关键字,使用async关键字可以将一个函数定义为协程函数,使用awiat关键字可以在遇到IO的时候挂起当前协程(也就是任务),去执行其他协程。
await + 可等待的对象(协程对象、Future对象、Task对象 -> IO等待)
注意:在python3.4中是通过asyncio装饰器定义协程,在python3.8中已经移除了asyncio装饰器。
事件循环,可以把他当做是一个while循环,这个while循环在周期性的运行并执行一些协程(任务),在特定条件下终止循环。
loop = asyncio.get_event_loop():生成一个事件循环
loop.run_until_complete(任务):将任务放到事件循环
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。除了使用 asyncio.create_task() 函数以外,还可以用低层级的 loop.create_task() 或 ensure_future() 函数。不建议手动实例化 Task 对象。
本质上是将协程对象封装成task对象,并将协程立即加入事件循环,同时追踪协程的状态。
注意:asyncio.create_task() 函数在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用 asyncio.ensure_future() 函数。
下面结合async & awiat、事件循环和Task看一个示例
示例一:
*注意:python 3.7以后增加了asyncio.run(协程对象),效果等同于loop = asyncio.get_event_loop(),loop.run_until_complete(协程对象)
*示例二:
注意:asyncio.wait 源码内部会对列表中的每个协程执行ensure_future从而封装为Task对象,所以在和wait配合使用时task_list的值为[func(),func()] 也是可以的。
示例三:
pythonä¸å¤è¿ç¨+åç¨ç使ç¨ä»¥å为ä»ä¹è¦ç¨å®
åé¢è®²äºä¸ºä»ä¹pythonéæ¨èç¨å¤è¿ç¨èä¸æ¯å¤çº¿ç¨ï¼ä½æ¯å¤è¿ç¨ä¹æå ¶èªå·±çéå¶ï¼ç¸æ¯çº¿ç¨æ´å 笨éãåæ¢èæ¶æ´é¿ï¼å¹¶ä¸å¨pythonçå¤è¿ç¨ä¸ï¼è¿ç¨æ°éä¸æ¨èè¶ è¿CPUæ ¸å¿æ°ï¼ä¸ä¸ªè¿ç¨åªæä¸ä¸ªGILï¼æ以ä¸ä¸ªè¿ç¨åªè½è·æ»¡ä¸ä¸ªCPUï¼ï¼å 为ä¸ä¸ªè¿ç¨å ç¨ä¸ä¸ªCPUæ¶è½å åå©ç¨æºå¨çæ§è½ï¼ä½æ¯è¿ç¨å¤äºå°±ä¼åºç°é¢ç¹çè¿ç¨åæ¢ï¼åèå¾ä¸å¿å¤±ãä¸è¿ç¹æ®æ åµï¼ç¹æIOå¯éåä»»å¡ï¼ä¸ï¼å¤çº¿ç¨æ¯æ¯å¤è¿ç¨å¥½ç¨çã
举个ä¾åï¼ç»ä½ Wæ¡urlï¼éè¦ä½ ææ¯ä¸ªurl对åºç页é¢æåä¿åèµ·æ¥ï¼è¿ç§æ¶åï¼åå使ç¨å¤è¿ç¨ï¼ææè¯å®æ¯å¾å·®çã为ä»ä¹å¢ï¼
ä¾å¦æ¯æ¬¡è¯·æ±ççå¾ æ¶é´æ¯2ç§ï¼é£ä¹å¦ä¸ï¼å¿½ç¥cpu计ç®æ¶é´ï¼ï¼
1ãåè¿ç¨+å线ç¨ï¼éè¦2ç§*W=Wç§==.个å°æ¶==.3天ï¼è¿ä¸ªé度ææ¾æ¯ä¸è½æ¥åç
2ãåè¿ç¨+å¤çº¿ç¨ï¼ä¾å¦æ们å¨è¿ä¸ªè¿ç¨ä¸å¼äºä¸ªå¤çº¿ç¨ï¼æ¯1ä¸è½å¤æååé度ï¼ä¹å°±æ¯å¤§çº¦4.天è½å¤å®æWæ¡æåï¼è¯·æ³¨æï¼è¿éçå®é æ§è¡æ¯ï¼çº¿ç¨1éè§äºé»å¡ï¼CPUåæ¢å°çº¿ç¨2å»æ§è¡ï¼éè§é»å¡ååæ¢å°çº¿ç¨3ççï¼ä¸ªçº¿ç¨é½é»å¡åï¼è¿ä¸ªè¿ç¨å°±é»å¡äºï¼èç´å°æ个线ç¨é»å¡å®æåï¼è¿ä¸ªè¿ç¨æè½ç»§ç»æ§è¡ï¼æ以é度ä¸æå大约è½å°åï¼è¿é忽ç¥äºçº¿ç¨åæ¢å¸¦æ¥çå¼éï¼å®é ä¸çæååºè¯¥æ¯ä¸è½è¾¾å°åçï¼ï¼ä½æ¯éè¦èèçæ¯çº¿ç¨çåæ¢ä¹æ¯æå¼éçï¼æ以ä¸è½æ éçå¯å¨å¤çº¿ç¨ï¼å¼W个线ç¨è¯å®æ¯ä¸é è°±çï¼
3ãå¤è¿ç¨+å¤çº¿ç¨ï¼è¿éå°±å害äºï¼ä¸è¬æ¥è¯´ä¹æå¾å¤äººç¨è¿ä¸ªæ¹æ³ï¼å¤è¿ç¨ä¸ï¼æ¯ä¸ªè¿ç¨é½è½å ä¸ä¸ªcpuï¼èå¤çº¿ç¨ä»ä¸å®ç¨åº¦ä¸ç»è¿äºé»å¡ççå¾ ï¼æ以æ¯åè¿ç¨ä¸çå¤çº¿ç¨åæ´å¥½ä½¿äºï¼ä¾å¦æ们å¼ä¸ªè¿ç¨ï¼æ¯ä¸ªè¿ç¨éå¼W个线ç¨ï¼æ§è¡çé度ç论ä¸æ¯æ¯åè¿ç¨å¼W个线ç¨å¿«å以ä¸çï¼ä¸ºä»ä¹æ¯å以ä¸èä¸æ¯åï¼ä¸»è¦æ¯cpuåæ¢W个线ç¨çæ¶èè¯å®æ¯åæ¢W个è¿ç¨å¤§å¾å¤ï¼èèå°è¿é¨åå¼éï¼æ以æ¯å以ä¸ï¼ã
è¿ææ´å¥½çæ¹æ³åï¼çæ¡æ¯è¯å®çï¼å®å°±æ¯ï¼
4ãåç¨ï¼ä½¿ç¨å®ä¹åæ们å 讲讲what/why/howï¼å®æ¯ä»ä¹/为ä»ä¹ç¨å®/æä¹ä½¿ç¨å®ï¼
whatï¼
åç¨æ¯ä¸ç§ç¨æ·çº§çè½»é级线ç¨ãåç¨æ¥æèªå·±çå¯åå¨ä¸ä¸æåæ ãåç¨è°åº¦åæ¢æ¶ï¼å°å¯åå¨ä¸ä¸æåæ ä¿åå°å ¶ä»å°æ¹ï¼å¨ååæ¥çæ¶åï¼æ¢å¤å åä¿åçå¯åå¨ä¸ä¸æåæ ãå æ¤ï¼
åç¨è½ä¿çä¸ä¸æ¬¡è°ç¨æ¶çç¶æï¼å³ææå±é¨ç¶æçä¸ä¸ªç¹å®ç»åï¼ï¼æ¯æ¬¡è¿ç¨éå ¥æ¶ï¼å°±ç¸å½äºè¿å ¥ä¸ä¸æ¬¡è°ç¨çç¶æï¼æ¢ç§è¯´æ³ï¼è¿å ¥ä¸ä¸æ¬¡ç¦»å¼æ¶æå¤é»è¾æµçä½ç½®ã
å¨å¹¶åç¼ç¨ä¸ï¼åç¨ä¸çº¿ç¨ç±»ä¼¼ï¼æ¯ä¸ªåç¨è¡¨ç¤ºä¸ä¸ªæ§è¡åå ï¼æèªå·±çæ¬å°æ°æ®ï¼ä¸å ¶å®åç¨å ±äº«å ¨å±æ°æ®åå ¶å®èµæºã
whyï¼
ç®å主æµè¯è¨åºæ¬ä¸é½éæ©äºå¤çº¿ç¨ä½ä¸ºå¹¶å设æ½ï¼ä¸çº¿ç¨ç¸å ³çæ¦å¿µæ¯æ¢å å¼å¤ä»»å¡ï¼Preemptive multitaskingï¼ï¼èä¸åç¨ç¸å ³çæ¯åä½å¼å¤ä»»å¡ã
ä¸ç®¡æ¯è¿ç¨è¿æ¯çº¿ç¨ï¼æ¯æ¬¡é»å¡ãåæ¢é½éè¦é·å ¥ç³»ç»è°ç¨(system call)ï¼å 让CPUè·æä½ç³»ç»çè°åº¦ç¨åºï¼ç¶ååç±è°åº¦ç¨åºå³å®è¯¥è·åªä¸ä¸ªè¿ç¨(线ç¨)ã
èä¸ç±äºæ¢å å¼è°åº¦æ§è¡é¡ºåºæ æ³ç¡®å®çç¹ç¹ï¼ä½¿ç¨çº¿ç¨æ¶éè¦é常å°å¿å°å¤çåæ¥é®é¢ï¼èåç¨å®å ¨ä¸åå¨è¿ä¸ªé®é¢ï¼äºä»¶é©±å¨åå¼æ¥ç¨åºä¹æåæ ·çä¼ç¹ï¼ã
å 为åç¨æ¯ç¨æ·èªå·±æ¥ç¼åè°åº¦é»è¾çï¼å¯¹CPUæ¥è¯´ï¼åç¨å ¶å®æ¯å线ç¨ï¼æ以CPUä¸ç¨å»èèæä¹è°åº¦ãåæ¢ä¸ä¸æï¼è¿å°±çå»äºCPUçåæ¢å¼éï¼æ以åç¨å¨ä¸å®ç¨åº¦ä¸å好äºå¤çº¿ç¨ã
how:
pythonéé¢æä¹ä½¿ç¨åç¨ï¼çæ¡æ¯ä½¿ç¨geventï¼ä½¿ç¨æ¹æ³ï¼çè¿é
使ç¨åç¨ï¼å¯ä»¥ä¸å线ç¨å¼éçéå¶ï¼æå°è¯è¿ä¸æ¬¡æWæ¡urlæ¾å¨åè¿ç¨çåç¨éæ§è¡ï¼å®å ¨æ²¡é®é¢ã
æ以ææ¨èçæ¹æ³ï¼æ¯å¤è¿ç¨+åç¨ï¼å¯ä»¥çä½æ¯æ¯ä¸ªè¿ç¨éé½æ¯å线ç¨ï¼èè¿ä¸ªå线ç¨æ¯åç¨åçï¼
å¤è¿ç¨+åç¨ä¸ï¼é¿å¼äºCPUåæ¢çå¼éï¼åè½æå¤ä¸ªCPUå åå©ç¨èµ·æ¥ï¼è¿ç§æ¹å¼å¯¹äºæ°æ®éè¾å¤§çç¬è«è¿ææ件读åä¹ç±»çæçæåæ¯å·¨å¤§çã
å°ä¾åï¼
[python] view plain copy
#-*- coding=utf-8 -*-
import requests
from multiprocessing import Process
import gevent
from gevent import monkey; monkey.patch_all()
import sys
reload(sys)
sys.setdefaultencoding('utf8')
def fetch(url):
try:
s = requests.Session()
r = s.get(url,timeout=1)#å¨è¿éæå页é¢
except Exception,e:
print e
return ''
def process_start(url_list):
tasks = []
for url in url_list:
tasks.append(gevent.spawn(fetch,url))
gevent.joinall(tasks)#使ç¨åç¨æ¥æ§è¡
def task_start(filepath,flag = ):#æ¯Wæ¡urlå¯å¨ä¸ä¸ªè¿ç¨
with open(filepath,'r') as reader:#ä»ç»å®çæ件ä¸è¯»åurl
url = reader.readline().strip()
url_list = []#è¿ä¸ªlistç¨äºåæ¾åç¨ä»»å¡
i = 0 #计æ°å¨ï¼è®°å½æ·»å äºå¤å°ä¸ªurlå°åç¨éå
while url!='':
i += 1
url_list.append(url)#æ¯æ¬¡è¯»ååºurlï¼å°urlæ·»å å°éå
if i == flag:#ä¸å®æ°éçurlå°±å¯å¨ä¸ä¸ªè¿ç¨å¹¶æ§è¡
p = Process(target=process_start,args=(url_list,))
p.start()
url_list = [] #éç½®urléå
i = 0 #é置计æ°å¨
url = reader.readline().strip()
if url_list not []:#è¥éåºå¾ªç¯åä»»å¡éåéè¿æurlå©ä½
p = Process(target=process_start,args=(url_list,))#æå©ä½çurlå ¨é½æ¾å°æåè¿ä¸ªè¿ç¨æ¥æ§è¡
p.start()
if __name__ == '__main__':
task_start('./testData.txt')#读åæå®æ件
ç»å¿çåå¦ä¼åç°ï¼ä¸é¢çä¾åä¸éèäºä¸ä¸ªé®é¢ï¼è¿ç¨çæ°éä¼éçurlæ°éçå¢å èä¸æå¢å ï¼æ们å¨è¿éä¸ä½¿ç¨è¿ç¨æ± multiprocessing.Poolæ¥æ§å¶è¿ç¨æ°éçåå æ¯multiprocessing.Poolågeventæå²çªä¸è½åæ¶ä½¿ç¨ï¼ä½æ¯æå ´è¶£çåå¦å¯ä»¥ç 究ä¸ä¸gevent.poolè¿ä¸ªåç¨æ± ã
Python 协程-asyncio、async/await
理解Python协程,尤其是asyncio和async/await机制,对于提升异步编程能力至关重要。这两个特性允许在Python中以一种优雅且高效的方式处理非阻塞性任务。
在使用asyncio进行异步编程时,可以将一系列任务组合到一个协程中,使用await asyncio.gather()函数来并发执行这些任务。这种方式允许在处理多个任务时提高效率,避免了传统同步编程中可能出现的阻塞问题。
以一个简单的例子说明,假设我们有两个协程a()和b(),分别代表两个耗时的操作。通过将await asyncio.gather(a(), b())添加到程序中,我们能够在等待这两个任务完成的同时进行其他操作,从而实现更高效的资源利用。
进一步探索Python中的异步接口和同步实现,Task类提供了一种实现异步生产者消费者模型的途径。在这样的模型中,生产者创建任务并将结果传递给消费者,消费者处理这些结果。通过使用Task类,可以轻松地管理这些任务,并利用await关键字在需要等待任务完成时暂停程序执行。
最后,学习如何构建和利用Python的生产者消费者模型,可以参考相关资源。这种模型在处理大量数据流时特别有用,例如在网络编程、数据处理和并发计算场景中。