<p>这对使用Quamash/asyncio进行异步应用程序的任何人都可能有用。在</p>
<p>它以@eyllanesc为例,在执行器中分派一个CPU绑定的任务,并删除对GTT的依赖。在</p>
<p>同样出于我的目的,我不知道CPU绑定需要多长时间,所以我将progress对话框的最小值和最大值都设置为零。这有一个很好的效果,就是在任务完成之前对进度条设置动画。但是,在执行此操作时必须手动调用<code>cancel()</code>方法,因为进度对话框无法知道它何时完成。这是在附加到未来的回调中完成的。在</p>
<pre><code>def main():
import sys
import time
import quamash
import asyncio
import concurrent
import logging
import random
import PyQt5
# Integrate event loops
app = PyQt5.QtWidgets.QApplication(sys.argv)
loop = quamash.QEventLoop(app)
asyncio.set_event_loop(loop)
loop.set_debug(False) # optional
# Config logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('quamash').setLevel(logging.ERROR)
# Print exception before crash!
def except_hook(cls, exception, traceback):
sys.__excepthook__(cls, exception, traceback)
sys.excepthook = except_hook
class MainWindow(PyQt5.QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.exitRequest = asyncio.Event()
self.genAudioButton = PyQt5.QtWidgets.QPushButton('Generate', self)
self.genAudioButton.clicked.connect(self.generate)
self.setCentralWidget(self.genAudioButton)
self.show()
def generate(self):
self.progress = PyQt5.QtWidgets.QProgressDialog('Work in progress...', None, 0, 0, self)
self.progress.setWindowTitle("Calculation")
self.progress.setWindowModality(PyQt5.QtCore.Qt.WindowModal)
self.progress.show()
self.progress.setValue(0)
# As the loop to run the coroutine
loop = asyncio.get_event_loop()
loop.create_task(self.doGenerate())
def closeEvent(self, event):
""" Called when the windows closes.
"""
self.exitRequest.set()
def cpuBound(self):
""" Just wait 2s or raise an exception 50% of the time to test error handling.
"""
# %50 change of raising an exception
time.sleep(1.0)
if random.random() < 0.5:
time.sleep(1.0)
else:
raise RuntimeError(
("If the CPU bound task fails you can raise "
"an exception that can be caught and displayed"
" like this!")
)
def onComplete(self, future):
""" Callback which contains the future that has completed.
"""
# Dismiss the progress popup widget before we (possibly)
# display a popup with an error message.
self.progress.cancel()
# Check if we got a result or an exception!
try:
result = future.result()
except Exception as e:
errBox = PyQt5.QtWidgets.QMessageBox()
errBox.setWindowTitle('Error')
errBox.setText('Error: ' + str(e))
errBox.addButton(PyQt5.QtWidgets.QMessageBox.Ok)
errBox.exec()
async def doGenerate(self):
""" The coroutine that is added to the event loop when the button is pressed.
"""
loop = asyncio.get_event_loop()
with concurrent.futures.ThreadPoolExecutor() as pool:
future = loop.run_in_executor(pool, self.cpuBound)
# This call back handles the result or possible exception
future.add_done_callback(self.onComplete)
# Block here until complete
result = await future
# Startup application
_window = MainWindow()
_window.show()
with loop:
loop.run_until_complete(_window.exitRequest.wait())
if __name__ == '__main__':
main()
</code></pre>