首先,我像这样运行代码,重试工作正常。
# -*- coding:utf-8 -*-
from retrying import retry
import asyncio
import time
num = 0;
def retry_if_result_none(result):
return result is None
@retry(retry_on_result=retry_if_result_none)
def get_result():
global num;
num += 1;
if num < 10:
print('Retry.....');
return None;
else:
return True;
time.sleep(1);
def call():
end = get_result();
if end:
print('ok');
else:
print('over')
if __name__ == '__main__':
call();
Output:
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
ok
第二,我像这样编辑代码,然后再次运行,但是收到不同的结果。
# -*- coding:utf-8 -*-
from retrying import retry
import asyncio
import time
num = 0;
def retry_if_result_none(result):
# print("retry_if_result_none")
return result is None
@retry(retry_on_result=retry_if_result_none)
async def get_result():
global num;
num += 1;
if num < 10:
print('Retry.....');
return None;
else:
return True;
time.sleep(1);
async def call():
end = await get_result();
if end:
print('ok');
else:
print('over')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(call())
Output:
Retry.....
over
如所示,重试在第二个代码中不起作用。区别在于我将call()放入loop.run_until_complete方法中,如何解决此问题?
答案 0 :(得分:0)
相关的区别是,在第二个代码片段中,您不再装饰一个函数,而是一个协程。它们仅在事件循环中执行后返回。
将result
的调试打印添加到您的检查功能,并使用同步代码示例运行它,将显示预期的结果:
def retry_if_result_none(result):
print(result)
return result is None
Retry.....
None
Retry.....
None
True # Note: I have set the condition to num < 3
ok
如果您对异步版本执行相同操作,则会看到问题:
<coroutine object get_result at 0x0322EF90>
Retry.....
over
因此result
实际上是协程本身,而不是结果。因此,您的retry_if_result_none
函数返回False
,并且重试循环在第一次迭代后终止。
基本上,这是一个计时问题。您的同步装饰器与事件循环中协程的异步执行不同步(非常有意思)。
您必须使用异步装饰器才能await
协程的结果。我已经采用this basic but functional asnyc retry decorator来根据您函数的返回值做出决定,就像retrying
中的函数一样。
请注意,内部wrapper
函数是一个协程,它await
装饰了协程get_result
的结果。
def tries(func):
def func_wrapper(f):
async def wrapper(*args, **kwargs):
while True:
try:
if func(await f(*args, **kwargs)):
continue
else:
break
except Exception as exc:
pass
return True
return wrapper
return func_wrapper
@tries(retry_if_result_none)
async def get_result():
[...]
在异步代码上使用此代码会产生预期的输出:
Retry.....
None
Retry.....
None
[...]
Retry.....
None
True
ok
除了在get_result
函数上打开装饰器和print
函数中提到的retry_if_result_none
语句以外,其余代码均未更改。