如何将回调和期货与 asyncio 和 PyQt5 事件循环一起使用?
How to use callbacks and futures with asyncio and the PyQt5 event loop?
这是我编写的一个小测试程序,试图了解如何将 PyQt 事件循环与 asyncio
:
一起使用
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
from PyQt5 import QtCore
import qasync
import asyncio
async def main():
app = QApplication(sys.argv)
asyncio.set_event_loop(qasync.QEventLoop(app))
window = QMainWindow()
window.setGeometry(100, 100, 200, 200)
button = QPushButton(window)
button.move(50, 50)
button.resize(100, 100)
button.setText('Run')
future = None
def run_action():
future.set_result('run clicked')
button.clicked.connect(run_action)
window.setWindowTitle('Testing async event loop')
window.show()
await asyncio.sleep(1)
i = 0
while True:
future = asyncio.get_event_loop().create_future()
result = await future
i += 1
if i == 4:
break
print("Done")
asyncio.run(main())
这给了我以下错误:
Traceback (most recent call last):
File "/home/hakon/test/python/async/./t.py", line 36, in <module>
asyncio.run(main())
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/home/hakon/test/python/async/./t.py", line 25, in main
await asyncio.sleep(1)
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/tasks.py", line 654, in sleep
return await future
RuntimeError: Task <Task pending name='Task-1' coro=<main() running at /home/hakon/test/python/async/./t.py:25> cb=[_run_until_complete_cb() at /home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/base_events.py:184]> got Future <Future pending> attached to a different loop
知道我在这里遗漏了什么吗?我该如何改进此代码?
问题是您是 运行 一个事件循环,然后您刚刚创建了 Qt 事件循环。有 2 种可能的解决方案:
在执行协程main之前设置eventloop:
import asyncio
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
import qasync
async def main():
window = QMainWindow()
window.setGeometry(100, 100, 200, 200)
button = QPushButton(window)
button.move(50, 50)
button.resize(100, 100)
button.setText("Run")
future = None
def run_action():
if future is not None:
future.set_result("run clicked")
button.clicked.connect(run_action)
window.setWindowTitle("Testing async event loop")
window.show()
await asyncio.sleep(1)
i = 0
while True:
future = asyncio.get_event_loop().create_future()
result = await future
i += 1
if i == 4:
break
print("Done")
app = QApplication(sys.argv)
loop = qasync.QEventLoop(app)
asyncio.set_event_loop(loop)
with loop:
loop.run_until_complete(main())
或使用qasync.run():
import asyncio
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
import qasync
async def main():
window = QMainWindow()
window.setGeometry(100, 100, 200, 200)
button = QPushButton(window)
button.move(50, 50)
button.resize(100, 100)
button.setText("Run")
future = None
def run_action():
if future is not None:
future.set_result("run clicked")
button.clicked.connect(run_action)
window.setWindowTitle("Testing async event loop")
window.show()
await asyncio.sleep(1)
i = 0
while True:
future = asyncio.get_event_loop().create_future()
result = await future
i += 1
if i == 4:
break
print("Done")
qasync.run(main())
这是我编写的一个小测试程序,试图了解如何将 PyQt 事件循环与 asyncio
:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
from PyQt5 import QtCore
import qasync
import asyncio
async def main():
app = QApplication(sys.argv)
asyncio.set_event_loop(qasync.QEventLoop(app))
window = QMainWindow()
window.setGeometry(100, 100, 200, 200)
button = QPushButton(window)
button.move(50, 50)
button.resize(100, 100)
button.setText('Run')
future = None
def run_action():
future.set_result('run clicked')
button.clicked.connect(run_action)
window.setWindowTitle('Testing async event loop')
window.show()
await asyncio.sleep(1)
i = 0
while True:
future = asyncio.get_event_loop().create_future()
result = await future
i += 1
if i == 4:
break
print("Done")
asyncio.run(main())
这给了我以下错误:
Traceback (most recent call last):
File "/home/hakon/test/python/async/./t.py", line 36, in <module>
asyncio.run(main())
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/home/hakon/test/python/async/./t.py", line 25, in main
await asyncio.sleep(1)
File "/home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/tasks.py", line 654, in sleep
return await future
RuntimeError: Task <Task pending name='Task-1' coro=<main() running at /home/hakon/test/python/async/./t.py:25> cb=[_run_until_complete_cb() at /home/hakon/.pyenv/versions/3.9.4/lib/python3.9/asyncio/base_events.py:184]> got Future <Future pending> attached to a different loop
知道我在这里遗漏了什么吗?我该如何改进此代码?
问题是您是 运行 一个事件循环,然后您刚刚创建了 Qt 事件循环。有 2 种可能的解决方案:
在执行协程main之前设置eventloop:
import asyncio import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton import qasync async def main(): window = QMainWindow() window.setGeometry(100, 100, 200, 200) button = QPushButton(window) button.move(50, 50) button.resize(100, 100) button.setText("Run") future = None def run_action(): if future is not None: future.set_result("run clicked") button.clicked.connect(run_action) window.setWindowTitle("Testing async event loop") window.show() await asyncio.sleep(1) i = 0 while True: future = asyncio.get_event_loop().create_future() result = await future i += 1 if i == 4: break print("Done") app = QApplication(sys.argv) loop = qasync.QEventLoop(app) asyncio.set_event_loop(loop) with loop: loop.run_until_complete(main())
或使用qasync.run():
import asyncio import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton import qasync async def main(): window = QMainWindow() window.setGeometry(100, 100, 200, 200) button = QPushButton(window) button.move(50, 50) button.resize(100, 100) button.setText("Run") future = None def run_action(): if future is not None: future.set_result("run clicked") button.clicked.connect(run_action) window.setWindowTitle("Testing async event loop") window.show() await asyncio.sleep(1) i = 0 while True: future = asyncio.get_event_loop().create_future() result = await future i += 1 if i == 4: break print("Done") qasync.run(main())