[英]How to implement in python given two coroutine, keep run one until the other finished
python asyncio lib 非常新,並且一直在努力實現保持活動狀態的任務。 我想同時運行一個 cpu 密集型任務和一個保活任務。 保持活動應該定期運行,直到 cpu 密集型完成。
import asyncio
import time
async def cpu_intensive():
print("cpu_intensive for 3 seconds")
delay = 3
close_time = time.time() + delay
while True:
if time.time() > close_time:
break
async def keep_alive():
print("keep alive for 1 second") # My real use case is I want to send a heart beat message every x seconds until cpu intensive finished
await asyncio.sleep(1)
async def main():
cpu_intensive_task = asyncio.create_task(cpu_intensive())
keep_alive_task = asyncio.create_task(keep_alive())
print(f"Started at {time.strftime('%X')}")
# TODO: Not sure how to achieve the expected output
print(f"Finished at {time.strftime('%X')}")
asyncio.run(main())
'''
Expected Output
Started at 23:55:08
cpu_intensive 3 seconds
keep alive for 1 seconds
keep alive for 1 seconds
keep alive for 1 seconds
Finished at 23:55:11
'''
我瀏覽了 asyncio lib python 並嘗試了幾個 API 例如await
, run_coroutine_threadsafe
, asyncio.gather
。 但無法讓它工作。
您是否嘗試過使用線程? 您可以像這樣輕松實現它。
import threading
import time
from datetime import datetime
def cpu_intensive():
time.sleep(10) #this is the time consuming task
print("CPU INTENSTIVE TASK DONE")
def keep_alive():
now = datetime.now() # current date and time
date_time = now.strftime("%m/%d/%Y, %H:%M:%S")
print(f"{date_time} -- BUSY STATUS / SIGNAL CODE")
#Starting the cpu_intensive task
thread = threading.Thread(target=cpu_intensive)
now = datetime.now() # current date and time
date_time = now.strftime("%m/%d/%Y, %H:%M:%S")
print("STARTING CPU PROCESS: ", date_time)
thread.start()
# Doing something while the task is alive
while thread.is_alive():
keep_alive()
time.sleep(1)
thread.join()
print("TASK COMPLETE")
output 應如下所示
STARTING CPU PROCESS: 11/18/2021, 14:53:05
11/18/2021, 14:53:05 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:06 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:07 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:08 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:09 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:10 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:11 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:12 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:13 -- BUSY STATUS / SIGNAL CODE
11/18/2021, 14:53:14 -- BUSY STATUS / SIGNAL CODE
CPU INTENSTIVE TASK DONE
TASK COMPLETE
您也可以切換線程以保持 keep_alive。
我認為您可能將並發的概念與並行性混淆了。 讓我寫一些我在玩 asyncio 時的理解:
Parallel
:“物理”並發,其中可能有超過 1 行代碼同時執行。
multiprocessing
Asynchronous(await/async)
:“感知”並發,在任何給定時間執行的代碼不能超過 1 行,但通過上下文切換實現並發。 使用await
關鍵字來允許上下文更改。
asyncio
curio
trio
Asynchronous(time division)
:又名線程。 由於GIL ,python 中的線程在任何給定時間只能執行 1 行代碼。 因此與上述有相似之處。
threading
因此,對於任何 CPU 密集型工作負載,最好是並行化。
對於任何 IO 綁定工作負載(又名等待),最好異步編碼 - 因為我們不需要使用更多內核。
你需要在cpu_intensive
協程中await
一些東西。
如這篇SO 帖子所示,我們可以使用yield asyncio.sleep(0)
在工作負載中添加上下文切換點。 當然,這不是編寫異步代碼的理想方式,但如果您需要將此類 function 附加到異步代碼,這是一種方式。
另外,您需要在給定任務實例運行時循環keep_alive
,該檢查由asyncio.Task.done()
完成。
import asyncio
import time
async def cpu_intensive():
print("cpu_intensive for 3 seconds")
duration = 3
close_time = time.time() + duration
while True:
if time.time() > close_time:
break
await asyncio.sleep(0)
async def keep_alive(task: asyncio.Task):
while not task.done():
print("keep alive for 1 second")
# My real use case is I want to send a heart beat message every x seconds until cpu intensive finished
await asyncio.sleep(1)
async def main():
print(f"Started at {time.strftime('%X')}")
cpu_intensive_task = asyncio.create_task(cpu_intensive())
keep_alive_task = asyncio.create_task(keep_alive(cpu_intensive_task))
await keep_alive_task
print(f"Finished at {time.strftime('%X')}")
asyncio.run(main())
'''
Output:
Started at 16:16:42
cpu_intensive for 3 seconds
keep alive for 1 second
keep alive for 1 second
keep alive for 1 second
keep alive for 1 second
Finished at 16:16:46
'''
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.