python - Python - 无法通过 aiohttp 使用多个事件循环
问题描述
我正在尝试制作与此类似的代码。
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}
执行 a 会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
发生这种情况是因为服务器正在事件循环上运行并且FooFoo
想要重新运行循环。
我尝试过的解决方案:
- 使用 :将函数更改
hello
为同步函数foo = asyncio.get_event_loop().run_until_complete(FooFoo())
会产生相同的错误。 - 多处理:使用库在另一个线程/进程上运行服务器实例:池、线程、多处理、aioprocessing,这会产生不同的错误:
RuntimeError: Cannot run the event loop while another loop is running
- 这个 SO question给出了与多处理相同的错误。
- 这个问题也是如此。
我需要能够运行多个循环,或者如果您有更好的解决方案,我会接受它。
如果有帮助,我正在使用 python 3.6.8
解决方案
如果您将逻辑稍微更改为如下所示:
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)
你会得到它的工作。
更新鉴于OP评论的详细信息:
Foo Foo 类是通过对服务器的异步请求生成令牌的客户端。用户不应该实例化 FooFoo,然后再生成一个令牌。
我建议使用构建器模式来简化复杂对象的创建。我认为这种模式很适合这种情况。为了应用该模式,我们添加了一个新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)
该类FooFoo
将token
在实例化期间将其作为参数:
class FooFoo(object):
def __init__(self, token):
self.value = token
这样hello
请求处理程序将更改为:
async def hello(request):
foo = await FooFooBuilder.build()
return web.json_response({'ip': request.remote, 'value': foo.value})
使用这种方法,无需使用多个事件循环来完成任务。
推荐阅读
- actionscript-3 - 如何将数组随机保存在数组中
- r - 如何根据列制作“For循环”
- python - 如何合并具有重复键的字典列表
- python - 计算熊猫中一堆特定关键字出现次数的最有效方法是什么?
- rust - 为什么 if-let 表达式使用赋值运算符而不是相等运算符?
- python-3.x - 使用GPU的结果有什么区别?
- github-pages - 尽管在我的实时服务器上本地工作,但图像不会加载到 git hub 页面上。我检查了路径和 Capitilisation
- gml - 如何修复:代码未在某些帧上运行
- notepad++ - 安装在 Windows 7 Professional(以及 Windows 10)上的 Notepad++ 7.7.1 不会保存具有选定扩展名的新文件
- reactjs - 如何从挂钩中的选项卡中添加或删除项目?