Python3.7中的激发、遗忘和返回值
我有以下情况: 我有一个python服务器,在接收到请求时,需要解析一些信息,尽快将结果返回给用户,然后自己清理。 我尝试使用以下逻辑进行设计:Python3.7中的激发、遗忘和返回值,python,python-asyncio,python-3.7,producer-consumer,fire-and-forget,Python,Python Asyncio,Python 3.7,Producer Consumer,Fire And Forget,我有以下情况: 我有一个python服务器,在接收到请求时,需要解析一些信息,尽快将结果返回给用户,然后自己清理。 我尝试使用以下逻辑进行设计: Consumer: *==* (wait for result) *====(continue running)=====... \ / return Producer: *======(prase)====*=*
Consumer: *==* (wait for result) *====(continue running)=====...
\ / return
Producer: *======(prase)====*=*
\
Cleanup: *==========*
我一直在尝试使用异步任务和协同程序来实现这个场景,但没有效果。我尝试的每一件事最终要么是制作人在返回之前等待清理工作完成,要么是返回导致清理工作失败。
理论上,我可以让消费者在向用户显示结果后调用cleanup,但我不相信Python不知道如何“触发并忘记”并返回
例如,此代码:
导入异步IO
异步def Slowpoke():
打印(“我看到你因安提西而颤抖……”)
等待asyncio.sleep(3)
打印(“…打印!”)
异步def main():
task=asyncio.create_任务(Slowpoke())
回答“嗨!”
如果名称=“\uuuuu main\uuuuuuuu”:
打印(asyncio.run(main()))
尽管如此:
通过
返回:
I see you shiver with antici...
Hi!
而且永远也不会到达…或
我错过了什么
[…]创建一个新的事件循环,并在结束时将其关闭。[……]
在执行main
如果返回任务
对象并打印它,您将看到它处于取消状态:
async def main():
task = asyncio.create_task(Slowpoke())
# return "Hi!"
return task
if __name__ == "__main__":
print(asyncio.run(main()))
# I see you shiver with antici...
# <Task cancelled coro=<Slowpoke() done, defined at [...]>>
我成功地使用线程而不是异步IO使其工作:
import threading
import time
def Slowpoke():
print("I see you shiver with antici...")
time.sleep(3)
print("...pation")
def Rocky():
t = threading.Thread(name="thread", target=Slowpoke)
t.setDaemon(True)
t.start()
time.sleep(1)
return "HI!"
if __name__ == "__main__":
print(Rocky())
while True:
time.sleep(1)
asyncio
似乎并不特别适合这个问题。您可能需要简单的线程:
原因是,当家长完成任务时,您的任务被终止。通过抛出一个守护进程
线程,任务将继续运行,直到完成,或者直到程序退出
导入线程
导入时间
def Slowpoke():
尝试:
打印(“我看到你因安提西而颤抖……”)
时间。睡眠(3)
打印(“…打印!”)
除:
打印(“是”)
引发异常()
def main():
task=threading.Thread(目标=Slowpoke)
task.daemon=True
task.start()
回答“嗨!”
如果名称=“\uuuuu main\uuuuuuuu”:
打印(main())
尽管如此:
通过
(我希望我正确理解了你的问题。ASCII图像和文本描述在我脑海中并不完全一致。“嗨!”
是结果,“Antici..pation”
是清理,对吗?顺便说一句,我也喜欢那部音乐剧)
一种可能的基于asyncio的解决方案是尽快返回结果。返回将终止任务,这就是为什么需要启动并忘记清理。它必须附带停机代码,等待所有清理完成
import asyncio
async def Slowpoke():
print("I see you shiver with antici...")
await asyncio.sleep(3)
print("...pation!")
async def main():
result = "Hi!"
asyncio.create_task(Slowpoke())
return result
async def start_stop():
# you can create multiple tasks to serve multiple requests
task = asyncio.create_task(main())
print(await task)
# after the last request wait for cleanups to finish
this_task = asyncio.current_task()
all_tasks = [
task for task in asyncio.all_tasks()
if task is not this_task]
await asyncio.wait(all_tasks)
if __name__ == "__main__":
asyncio.run(start_stop())
另一个解决方案是使用其他方法(而不是返回)将结果传递给等待的任务,以便在解析之后立即开始清理。未来被认为是低水平的,但这里有一个例子
import asyncio
async def main(fut):
fut.set_result("Hi!")
# result delivered, continue with cleanup
print("I see you shiver with antici...")
await asyncio.sleep(3)
print("...pation!")
async def start_stop():
fut = asyncio.get_event_loop().create_future()
task = asyncio.create_task(main(fut))
print(await fut)
this_task = asyncio.current_task()
all_tasks = [
task for task in asyncio.all_tasks()
if task is not this_task]
await asyncio.wait(all_tasks)
if __name__ == "__main__":
asyncio.run(start_stop())
当您可能想永远运行_()
OP想要不等待地返回任务时,您正在运行主循环直到完成。是的,关键是返回值。不过,我确实找到了一个解决方案——使用TheReading.Oops,我为时已晚,hahaI添加了一个简单的解释,但您可能想稍微研究一下线程,以了解为什么您的任务在此之前会停止
import asyncio
async def main(fut):
fut.set_result("Hi!")
# result delivered, continue with cleanup
print("I see you shiver with antici...")
await asyncio.sleep(3)
print("...pation!")
async def start_stop():
fut = asyncio.get_event_loop().create_future()
task = asyncio.create_task(main(fut))
print(await fut)
this_task = asyncio.current_task()
all_tasks = [
task for task in asyncio.all_tasks()
if task is not this_task]
await asyncio.wait(all_tasks)
if __name__ == "__main__":
asyncio.run(start_stop())