【问题标题】:Python's asyncio works synchronouslyPython 的 asyncio 同步工作
【发布时间】:2015-04-05 12:42:11
【问题描述】:

我正在尝试利用 Python 的新 asyncio 库来发送异步 HTTP 请求。我想在发送每个请求之前等待几毫秒(timeout 变量) - 但当然 - 异步发送它们,而不是在每个请求发送后等待响应。

我正在做类似以下的事情:

@asyncio.coroutine
def handle_line(self, line, destination):
    print("Inside! line {} destination {}".format(line, destination))
    response = yield from aiohttp.request('POST', destination, data=line,
                               headers=tester.headers)
    print(response.status)
    return (yield from response.read())

@asyncio.coroutine
def send_data(self, filename, timeout):
    destination='foo'
    logging.log(logging.DEBUG, 'sending_data')
    with open(filename) as log_file:
        for line in log_file:
            try:
                json_event = json.loads(line)
            except ValueError as e:
                print("Error parsing json event")
            time.sleep(timeout)
            yield from asyncio.async(self.handle_line(json.dumps(json_event), destination))


loop=asyncio.get_event_loop().run_until_complete(send_data('foo.txt', 1))

我得到的输出(通过打印 200 个响应)看起来像这段代码正在同步运行。我做错了什么?

【问题讨论】:

    标签: python python-3.x asynchronous python-asyncio


    【解决方案1】:

    这里有几个问题:

    1. 你应该使用asyncio.sleep,而不是time.sleep,因为后者会阻塞事件循环。

    2. 1234563您处理每一行,等待处理完成,然后继续下一行。相反,您应该运行所有asyncio.async 调用而不等待,将返回的Task 对象保存到列表中,然后在您启动它们后使用asyncio.wait 等待它们全部完成。

    综合起来:

    @asyncio.coroutine
    def handle_line(self, line, destination):
        print("Inside! line {} destination {}".format(line, destination))
        response = yield from aiohttp.request('POST', destination, data=line,
                                   headers=tester.headers)
        print(response.status)
        return (yield from response.read())
    
    @asyncio.coroutine
    def send_data(self, filename, timeout):
        destination='foo'
        logging.log(logging.DEBUG, 'sending_data')
        tasks = []
        with open(filename) as log_file:
            for line in log_file:
                try:
                    json_event = json.loads(line)
                except ValueError as e:
                    print("Error parsing json event")
                yield from asyncio.sleep(timeout)
                tasks.append(asyncio.async(
                     self.handle_line(json.dumps(json_event), destination))
        yield from asyncio.wait(tasks)
    
    
    asyncio.get_event_loop().run_until_complete(send_data('foo.txt', 1))
    

    【讨论】:

    • 嗯...谢谢。但我不确定这是否正是我想要的。在将任务附加到任务列表之前,来自 asyncio.sleep 的产量将等待超时。 asyncio.wait 的 yield 将同时发送所有请求。我希望它们一个接一个地发送,每个请求之间有超时间隔。该代码不会在每个请求之间等待。它会一次全部发送。
    • @OhadBasan yield from asyncio.sleep(timeout) 行将使代码在开始每个任务之间等待timeout 秒,而不仅仅是在将其附加到任务列表之间。该任务实际上被添加到事件循环中并在您调用asyncio.async(task()) 时立即启动。您实际上不需要 yield from 任务即可开始执行。
    • @OhadBasan 将yield from 想成不是开始协程,而是等待完成。
    猜你喜欢
    • 2020-08-26
    • 2021-05-04
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多