asyncio创建任务和aiohttp,'没有运行的事件循环'。

4

我正在尝试使用aiohttp请求、asyncio任务来制作一个Pyqt5应用程序。我还使用了quamash包,因为它需要Python 3.7版本(在Python 3.10上不起作用)。我使用asyncio和quamash的主要原因是想进行请求操作而不冻结应用程序的GUI界面。

当我点击“开始”按钮并关闭应用程序时,会出现以下错误:

Task exception was never retrieved
future: <Task finished coro=<App.rotator() done, defined at C:\Users\Zsolt\Documents\python-example\stack_exmaple.py:37> exception=RuntimeError('no running event loop')>
Traceback (most recent call last):
  File "C:\Users\Zsolt\Documents\python-example\stack_exmaple.py", line 41, in rotator
    response = await get()
  File "C:\Users\Zsolt\Documents\python-example\stack_exmaple.py", line 51, in get
    async with session.get(pokemon_url) as resp:
  File "C:\Users\Zsolt\AppData\Local\Programs\Python\Python37\lib\site-packages\aiohttp\client.py", line 1138, in __aenter__
    self._resp = await self._coro
  File "C:\Users\Zsolt\AppData\Local\Programs\Python\Python37\lib\site-packages\aiohttp\client.py", line 533, in _request
    async with ceil_timeout(real_timeout.connect):
  File "C:\Users\Zsolt\AppData\Local\Programs\Python\Python37\lib\site-packages\aiohttp\helpers.py", line 734, in ceil_timeout
    return async_timeout.timeout(None)
  File "C:\Users\Zsolt\AppData\Local\Programs\Python\Python37\lib\site-packages\async_timeout\__init__.py", line 30, in timeout
    loop = _get_running_loop()
  File "C:\Users\Zsolt\AppData\Local\Programs\Python\Python37\lib\site-packages\async_timeout\__init__.py", line 236, in _get_running_loop
    return asyncio.get_running_loop()
RuntimeError: no running event loop

以下是完整代码:

from PyQt5.QtWidgets import *
from PyQt5.QtGui import QKeySequence, QPalette, QColor
from PyQt5.QtCore import Qt
from PyQt5 import QtGui, QtCore
import asyncio
import aiohttp
import quamash
import os.path
import json
import sys

class App(QWidget):

    run = 0
    response = ''
    def __init__(self, loop):
        super().__init__()

        btn = QPushButton('Start', self)
        btn.resize(btn.sizeHint())
        btn.clicked.connect(self.start)

        self.setGeometry(200, 200, 700, 400)
        self.display = QLabel(self)
        self.display.resize(200, 500)
        self.display.move(1, 50)

        self.count = 0
        self.show()
        self.loop = loop
        self.tasks = []
        self.tasks.append(loop.create_task(self.rotator()))

    async def rotator(self):
        while await asyncio.sleep(0, True):
            if (self.run == 1):
                self.count += 1
                response = await get()
                self.display.setText(str(response))
                  
    def start (self):
        self.run = 1            

async def get():
    async with aiohttp.ClientSession() as session:
        pokemon_url = 'https://pokeapi.co/api/v2/pokemon/151'
        async with session.get(pokemon_url) as resp:
            pokemon = await resp.json()
            print(pokemon)
            return pokemon
      
app = QApplication(sys.argv)
app.setApplicationName("Sample ;)")

loop = quamash.QEventLoop(app)
asyncio.set_event_loop(loop)

with loop:
    window = App(loop)
    window.show()
    loop.run_forever()

如果我注释掉response = await get(),它能够正常工作,计数器会自增1,并在self.display.setText(str(self.count))中显示变量。但我需要使用请求使其正常工作,以便从请求中打印出响应。


1
我通过安装aiohttp的先前版本来解决了这个错误。 pip install aiohttp==3.7.4 - Krisztian Nagy Zsolt
也许你可以将此作为答案发布,以便日后寻找解决方法的人能够看到。这是一个已知的错误吗?也许你可以在aiohttp的github上提交一个错误报告。对他们来说可能很有趣。 - thisisalsomypassword
好的,我已经发布了答案。我认为当我安装aiohttp时,它安装了\python37\lib\site-packages\aiohttp-3.8.1.dist-info\,我最初安装了这个版本,所以我在https://pypi.org/project/aiohttp/#history网站上查找了aiohttp的版本,并一直回溯到三月份,因为我记得那时它对我有用。 - Krisztian Nagy Zsolt
3个回答

3
TLDR; 使用qasync替换quamash。
在asyncio中,当异步代码执行时,任务始终存在。就像在多线程程序中至少存在主线程一样。如果quamash不遵循这个规则——那么这不是aiohttp的问题。
quamash不再维护,最新版本发布已经是3.5年前了。维护的后继者是qasync,它没有这个错误,并且可以与最新版本的aiohttp完美地配合使用。

1

值得一提的是,您还可以使用qtinter包来替换quamash,它支持Python 3.7到3.11。(免责声明:我是qtinter的作者。)

使用qtinter,最后几行代码需要更改如下:

app = QApplication(sys.argv)
app.setApplicationName("Sample ;)")

with qtinter.using_asyncio_from_qt():
    window = App(asyncio.get_running_loop())
    window.show()
    app.exec()

1

如果使用quamash包:

我通过安装先前版本的aiohttp来解决了错误。最初,我安装了aiohttp 3.8.1.dist版本。我也知道它在其他版本的aiohttp上可以正常工作,所以我查看了历史记录并发现需要卸载aiohttp并安装aiohttp==3.7.4。

命令:

pip uninstall aiohttp
pip install aiohttp==3.7.4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接