【问题标题】:While loop in async function throws StopIteration异步函数中的循环抛出 StopIteration
【发布时间】:2021-06-23 01:55:02
【问题描述】:

我正在开发一个程序,它异步向一个服务发送一堆请求。从现在开始我就有了一部分,那里只是请求并等待结果(ok_function)。现在我需要添加获得结果的部分,如果是 202 等待一段时间再试一次,因为它返回 200。

看起来像这样:

async def async_make_requests(parsed_data, url):
    async with aiohttp.ClientSession() as session:
        tasks = []
        for x, y in parsed_data.items():

            if something:
                tasks.append(
                    asyncio.ensure_future(
                        function_with_sleep(
                            session, x, y,
                        )
                    )
                )
             else:
                 tasks.append(
                    asyncio.ensure_future(
                        ok_function(
                            session, x, y,
                        )
                    )
                )   
        results = await asyncio.gather(*tasks)
    return results

async def function_with_sleep(session, x, y):
    not_processed_yet = True
    while not_processed_yet:
        async with session.get(x, data=y) as r:
            response = await r.json()
            status_code = r.status
        if status_code == 202:
            await asyncio.sleep(10)
        else:
            not_processed_yet = False
   ...

async def ok_function(session, x, y)
    async with session.post(x, data=y) as r:
        response = await r.json()
        status_code = r.status
    ...

在测试时:

    resp_processing = MockResponse(202, response)
    resp_ok = MockResponse(200, response)
    mocker.patch("aiohttp.ClientSession.get", side_effect=[resp_processing, resp_ok])
    return_value = await async_make_requests(parsed_data, "anyurl")

我得到:

  results = await asyncio.gather(*tasks) RuntimeError: coroutine raised StopIteration

ok_function 工作正常,function_with_sleep 只有在不重复自身且不休眠的情况下才能正常工作。

我不知道这里出了什么问题。

【问题讨论】:

    标签: python asynchronous python-asyncio


    【解决方案1】:

    代码看起来是正确的 - 虽然你没有说你的 session 也属于哪个 http 框架: 如果 r.json 在发出的请求中没有 json 主体时引发错误,则会传播此错误 - 如果是 StopIteration,它将按照描述中断 asyncIO.gather(否则,任务异常将设置在相应的任务)。

    尝试在获得 200 状态码之后调用await r.json(),而不是在测试状态码之前。如果您声称的行为确实是由您在问题中粘贴的代码引起的,这应该可以解决它。

    确实 - 似乎您正在使用 aiohttp 或基于它的东西:如果请求对象中没有可用的主体,它将在响应中调用 .read - 因为响应是模拟对象,这很可能触发StopIteration 异常。 - https://docs.aiohttp.org/en/stable/client_reference.html

    尽管如此,在您获得有意义的响应时尝试获取 JSON 正文是正确的做法,因此尝试向您的模拟添加正确的 read 响应是没有意义的。

    【讨论】:

    • 感谢您的回答。结果事实并非如此 - 但你的回答让我更深入地挖掘。正如您所提到的,代码似乎是正确的 - 这是真的。结果发现问题出在测试上——我正在测试执行 2 组数据——所以 1st 得到了 1st 202、2nd 200 响应。但它出现了 2 组,它没有重置,这就是提出 StopIteration 的原因。我需要做的就是 side_effect=itertools.cycle([resp_processing, resp_ok])
    猜你喜欢
    • 2017-09-30
    • 2020-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    • 2014-07-09
    • 1970-01-01
    相关资源
    最近更新 更多