简体   繁体   English

Python-无法与aiohttp一起使用多个事件循环

[英]Python - Unable to use multiple event loops with aiohttp

I am trying to make a code similar to this one work. 我正在尝试编写类似于此工作的代码。


class FooFoo:
    def __init__(self):
        loop = asyncio.get_event_loop()
        self.value = loop.run_until_complete(self.async_work())

    async def async_work(self):
        return 10


def build_server():
    app = web.Application()
    app.router.add_route('GET', '/', hello)
    web.run_app(app, 'localhost', '12000')

async def hello(request):
    foo = await FooFoo()
    return web.json_response{'ip': request.remote, 'value': foo.value}


Doing a curl http://127.0.0.1:/ yields this error: curl http://127.0.0.1:/产生此错误:

Error handling request
Traceback (most recent call last):
  File "/usr/local/lib64/python3.6/site-packages/aiohttp/web_protocol.py", line 418, in start
    resp = await task
  File "/usr/local/lib64/python3.6/site-packages/aiohttp/web_app.py", line 458, in _handle
    resp = await handler(request)
  File "/usr/local/lib64/python3.6/site-packages/aiohttp/web_urldispatcher.py", line 155, in handler_wrapper
    result = old_handler(request)
  File "test.py", line 36, in hello
    foo = asyncio.get_event_loop().run_until_complete(FooFoo())
  File "test.py", line 24, in __init__
    self.value = loop.run_until_complete(self.async_work())
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 471, in run_until_complete
    self.run_forever()
  File "/usr/lib64/python3.6/asyncio/base_events.py", line 425, in run_forever
    raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running

This happens because the server is running on the event loop and FooFoo is wants to rerun the loop. 发生这种情况是因为服务器在事件循环上运行,并且FooFoo要重新运行循环。

Solutions I've tried : 我尝试过的解决方案:

  • Changing the hello function into a synchronous one with : foo = asyncio.get_event_loop().run_until_complete(FooFoo()) , gives the same error. 使用以下命令将hello函数更改为同步函数: foo = asyncio.get_event_loop().run_until_complete(FooFoo())foo = asyncio.get_event_loop().run_until_complete(FooFoo())产生相同的错误。
  • Multiprocessing: Running the server instance on another thread/process using libraries : pool, threading, multiprocessing, aioprocessing, this gives a different error: 多重处理:使用库在另一个线程/进程上运行服务器实例:池,线程,多重处理,aioprocessing,这会产生不同的错误:
RuntimeError: Cannot run the event loop while another loop is running

I need to be able to run multiple loops, or if you have a better solution I'd take it. 我需要能够运行多个循环,或者如果您有更好的解决方案,我会接受。

If it helps I am using python 3.6.8 如果有帮助,我正在使用python 3.6.8

If you change the logic slightly to something like this: 如果您将逻辑略微更改为如下所示:

import asyncio

from aiohttp import web


class FooFoo(object):

    async def async_work(self):
        await asyncio.sleep(1)
        self.value = 10


async def hello(request):
    foo = FooFoo()
    await foo.async_work()

    return web.json_response({'ip': request.remote, 'value': foo.value})


def build_server():
    app = web.Application()
    app.router.add_route('GET', '/', hello)
    web.run_app(app, host='localhost', port=8080)

you'll get it working. 您将使其正常运行。

UPDATE Given the details from the OP comments: 更新给出了OP注释的详细信息:

the FooFoo class is a client that generates a token via asynchronous requests to a server. FooFoo类是一个客户端,它通过对服务器的异步请求生成令牌。 The user isn't supposed to instantiate FooFoo, then generate a token later. 用户不应该实例化FooFoo,然后再生成令牌。

I'd suggest using a builder pattern which is used to simplify creation of complex objects. 我建议使用一个构建器模式 ,该模式用于简化复杂对象的创建。 I think this pattern fits to this case just fine. 我认为这种模式适合这种情况。 In order to apply the pattern, we add a new FooFooBuilder class: 为了应用模式,我们添加了一个新的FooFooBuilder类:

async def request_token():
    await asyncio.sleep(1)

    return 42


class FooFooBuilder(object):
    @staticmethod
    async def build():
        token = await request_token()

        # Do token validation and error handling. 

        return FooFoo(token)

The FooFoo class will take the token as its argument during instantiation: FooFoo类在实例化期间将token作为其参数:

class FooFoo(object):
    def __init__(self, token):
        self.value = token

So that the hello request handler will change to: 这样, hello请求处理程序将更改为:

async def hello(request):
    foo = await FooFooBuilder.build()

    return web.json_response({'ip': request.remote, 'value': foo.value})

With this approach, there is no need to use multiple event loops to get things done. 使用这种方法,无需使用多个事件循环即可完成工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 python 3 asyncio和MotorClient:如何在多线程和多个事件循环中使用motor - python 3 asyncio and MotorClient: how to use motor with multithreading and multiple event loops 什么时候使用多个事件循环? - When to use multiple event loops? python aiohttp 进入现有的事件循环 - python aiohttp into existing event loop 如何使用python aiohttp库下载多个网页? - How to use python aiohttp library to download multiple webpages? 如何在python应用程序中使用两个事件循环 - How to use two event loops in python application Python 问题:无法在单独的线程或事件循环中运行连接 aiohttp 服务器 - Python Problems: Unable to run connexion aiohttp server in a separate thread or event loop 每个python进程的Asyncio事件循环(aioprocessing,多个事件循环) - Asyncio event loop per python process (aioprocessing, multiple event loops) Python API 无法使用 aiohttp 获取请求 - Python API Unable to GET request using aiohttp 将多进程与 API 请求和 Python 上的多个 for 循环一起使用 - Use multiprocess with API requests and multiple for loops on Python 如何在 python 中对多个变量使用 for 循环 - How to use for loops on multiple variables in python
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM