在 Python 3 中异步等待方法完成
Posted
技术标签:
【中文标题】在 Python 3 中异步等待方法完成【英文标题】:Asynchronically wait for a method to complete in Python 3 【发布时间】:2019-08-02 09:14:06 【问题描述】:考虑这个简化的例子:
def get_external_thing() -> str:
my_variable = a_blocking_operation()
my_variable.some_other_operation()
return my_variable
externally_gathered_thing = None
while True:
sleep(1)
externally_gathered_thing = get_external_thing()
if externally_gathered_thing:
do_something_1()
externally_gathered_thing = None
do_something_2()
这显然会进入循环,休眠一秒钟,然后进入get_external_thing()
并等待a_blocking_operation()
完成。只要get_external_thing()
正在运行,就不会执行任何其他操作。
如果get_external_thing()
没有完成,我想要完成的是强制我的循环继续并直接转到do_something_2()
。但是,如果 get_external_thing()
已经完成并且 externally_gathered_thing
有一些价值,我希望 do_something_1()
也能被执行。
我怎样才能纯粹在 Python 中完成它?我尝试使用这个示例来学习 asyncio,但没有设法生成任何工作示例。由于项目要求,asyncio 是首选,但不是必须的。
换句话说,无论get_external_thing()
的结果如何,我都希望每秒执行一次do_something_2()
(或每秒+一些小开销)。
注意:不要被while True
结构吓到,它被设计为在树莓派上连续运行:)
【问题讨论】:
当get_external_thing()
完成后,您想在下一次迭代中再次重新运行它吗?
我的实际流程更复杂,但是,如果我的问题是正确的,在get_external_thing()
完成后,我希望do_something_1()
被执行,然后externally_gathered_thing
设置为无,然后@987654337 @。但同样,这只是一个演示代码。 (我通过在if
中添加externally_gathered_thing
来更新代码)
再一次,在完成之后,get_external_thing()
是否应该在下一次迭代中重新运行?
是的,这将是首选流程。
TBH,在下一次迭代中不重新运行它不会有那么大的问题。
【参考方案1】:
对于此类任务,请查看concurrent.futures
模块。例如:
def get_external_thing() -> str:
my_variable = a_blocking_operation()
my_variable.some_other_operation()
return my_variable
externally_gathered_thing = None
executor = concurrent.futures.ThreadPoolExecutor()
working = None
while True:
if working is None:
# if no work is in progress, start the external task in a bg thread
working = executor.submit(get_external_thing)
try:
# wait for the external result, but no more than a second
externally_gathered_thing = working.result(timeout=1)
working = None
except concurrent.futures.TimeoutError:
# in case of timeout, proceed with our logic anyway, we'll get
# back to waiting in the next iteration
pass
if externally_gathered_thing is not None:
do_something_1()
externally_gathered_thing = None
do_something_2()
基于 asyncio 的解决方案是可能的,但它仍然必须在后台使用线程来等待阻塞操作(这就是 run_in_executor
的工作原理),因此它将 asyncio 的复杂性与线程的复杂性结合起来。
【讨论】:
这正是我一直在寻找的!非常感谢,Threading
似乎可以正确处理此任务。
我赞成这个答案,我会将其标记为已接受,因为在接下来的 2 小时内没有异步解决方案。
@Artur Asyncio 并非旨在处理像 a_blocking_operation()
这样的阻塞调用。您可以使用run_in_executor
将其硬塞到 asyncio 中,但它最终会在后台使用线程做同样的事情,给您带来 asyncio 和线程组合的复杂性,但没有 asyncio 的好处(取消等)。
好的,我相信了。感谢您的宝贵时间!以上是关于在 Python 3 中异步等待方法完成的主要内容,如果未能解决你的问题,请参考以下文章