考虑以下简化示例:
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是首选,但不是必须的。
换句话说,无论do_something_2()
的结果如何,我希望get_external_thing()
每秒执行一次(或每秒+少量开销)。
注意:不要被while True
构造所吓倒,它旨在在树莓派上连续运行:)
答案 0 :(得分: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的复杂性与线程。