You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5+asyncqt问题:asyncSlot()仍导致事件循环冻结

解决PyQt5+asyncqt异步槽函数中窗口无响应的问题

你的问题出在异步槽函数里仍然执行了同步阻塞的下载操作。asyncSlot只是让槽函数支持异步语法,但pytube的download()方法是同步阻塞的,它会占用Qt事件循环的主线程,导致窗口无法处理用户操作,直到下载完成。

要解决这个问题,需要把同步的下载任务放到单独的线程中执行,避免阻塞主线程。可以用asyncio.to_thread()(Python 3.9及以上)或者loop.run_in_executor()来实现。

修改后的完整代码如下:

import sys
import asyncio

from asyncqt import QEventLoop, asyncSlot
from pytube import YouTube

from PyQt5.QtWidgets import (
    QApplication, QWidget, QLabel, QLineEdit, QTextEdit, QPushButton,
    QVBoxLayout)


class MainWindow(QWidget):

    def __init__(self):
        super().__init__()

        self.setLayout(QVBoxLayout())

        self.lblStatus = QLabel('Idle', self)
        self.layout().addWidget(self.lblStatus)

        self.editUrl = QLineEdit('Hi!', self)
        self.layout().addWidget(self.editUrl)

        self.editResponse = QTextEdit('', self)
        self.layout().addWidget(self.editResponse)

        self.btnFetch = QPushButton('Fetch', self)
        self.btnFetch.clicked.connect(self.on_btnFetch_clicked)
        self.layout().addWidget(self.btnFetch)

    @asyncSlot()
    async def on_btnFetch_clicked(self):
        self.lblStatus.setText('downloading...')
        # 将同步下载任务放到线程中执行
        await asyncio.to_thread(self.download_video)
        self.lblStatus.setText('downloaded!')
    
    def download_video(self):
        # 这里是原有的同步下载逻辑,现在在单独线程执行
        yt = YouTube('https://www.youtube.com/watch?v=zG4uYN3n8zs')
        yt.streams.filter(resolution='720p').first().download('C:/Users/Andrew/Desktop')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()

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

    with loop:
        sys.exit(loop.run_forever())

关键说明:

  • asyncio.to_thread()会把传入的同步函数放到线程池的线程中执行,主线程的事件循环可以继续处理窗口的用户操作,不会被阻塞。
  • 如果你的Python版本低于3.9,可以用loop.run_in_executor()替代:
    # 先获取事件循环
    loop = asyncio.get_running_loop()
    await loop.run_in_executor(None, self.download_video)
    
  • 把下载逻辑单独抽成一个同步函数,放到线程中执行,这样异步槽函数只负责调度和状态更新,不会阻塞主线程。

内容的提问来源于stack exchange,提问作者Andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 16:35:50