簡體   English   中英

在單獨的線程中運行異步循環,信號來自和循環

[英]Running an asyncio loop in a separate thread, Signals from, and to loop

我正在嘗試制作一個在后台與多個 BLE 設備進行通信的 UI。 為此,我實現了一個運行 asyncio.loop 的單獨線程。 這是必要的,因為我使用 bleak 0.9.1 連接到設備。

使用信號和槽將數據從 UI 線程獲取到工作線程可以正常工作。 但是,它在另一個方向上不起作用。 據我所知,這是因為線程忙於運行循環並且永遠不會停止這樣做。 因此,它無法處理來自 UI 線程的輸入。

下面有一個顯示問題的示例代碼。

有沒有辦法在運行 asyncio 循環時處理線程中的輸入槽?

import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication, QVBoxLayout
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
import asyncio

class Test_Thread(QObject):
    signal_back = pyqtSignal(int)

    def __init__(self,
                 loop: asyncio.AbstractEventLoop,
                 parent=None):
        super(Test_Thread, self).__init__(parent)
        self.text = "Task1 not configured"
        self.loop = loop
        self.counter = 0

    @pyqtSlot(str)
    def set_text_slot(self, txt):
        self.text = txt

    async def do_stuff1(self):
        while True:
            print(self.text)
            await asyncio.sleep(2.0)

    async def do_stuff2(self):
        while True:
            self.counter += 1
            self.signal_back.emit(self.counter)
            await asyncio.sleep(1.0)

    def work(self):
        #run the event loop
        try:
            asyncio.ensure_future(self.do_stuff1(), loop=self.loop)
            asyncio.ensure_future(self.do_stuff2(), loop=self.loop)
            self.loop.run_forever()
        finally:
            print("Disconnect...")


class Window(QWidget):

    set_text_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        super(Window, self).__init__()
        self.initUi()
        self.startThread()

    def initUi(self):
        layout = QVBoxLayout()
        self.button = QPushButton('User input')
        self.button.clicked.connect(self.sendtotask)
        layout.addWidget(self.button)
        self.setLayout(layout)
        self.show()

    def startThread(self):
        loop = asyncio.get_event_loop()
        self.asyciothread = Test_Thread(loop)
        self.thread = QThread()
        self.asyciothread.moveToThread(self.thread)

        self.set_text_signal.connect(self.asyciothread.set_text_slot)
        self.asyciothread.signal_back.connect(self.receivefromthread)
        self.thread.started.connect(self.asyciothread.work)

        self.thread.start()

    @pyqtSlot(int)
    def receivefromthread(self, number):
        print(str(number))

    def sendtotask(self):
        self.set_text_signal.emit("Task: Configured")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    ui = Window()
    ui.show()
    sys.exit(app.exec_())

沒有必要使用線程來將 asyncio 與 Qt 一起使用,因為有像asyncqtqasync這樣的庫可以啟用它:

import asyncio
import sys

from PyQt5.QtWidgets import QWidget, QPushButton, QApplication, QVBoxLayout
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot

from asyncqt import QEventLoop
# from qasync import QEventLoop


class Worker(QObject):
    signal_back = pyqtSignal(int)

    def __init__(self, loop: asyncio.AbstractEventLoop, parent=None):
        super(Worker, self).__init__(parent)
        self.text = "Task1 not configured"
        self.loop = loop
        self.counter = 0

    @pyqtSlot(str)
    def set_text_slot(self, txt):
        self.text = txt

    async def do_stuff1(self):
        while True:
            print(self.text)
            await asyncio.sleep(2.0)

    async def do_stuff2(self):
        while True:
            self.counter += 1
            self.signal_back.emit(self.counter)
            await asyncio.sleep(1.0)

    def work(self):
        asyncio.ensure_future(self.do_stuff1(), loop=self.loop)
        asyncio.ensure_future(self.do_stuff2(), loop=self.loop)


class Window(QWidget):
    set_text_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        super(Window, self).__init__()
        self.initUi()
        self.start_task()

    def initUi(self):
        layout = QVBoxLayout(self)
        self.button = QPushButton("User input")
        self.button.clicked.connect(self.sendtotask)
        layout.addWidget(self.button)

    def start_task(self):
        loop = asyncio.get_event_loop()
        self.worker = Worker(loop)
        self.set_text_signal.connect(self.worker.set_text_slot)
        self.worker.signal_back.connect(self.receive_from_worker)
        self.worker.work()

    @pyqtSlot(int)
    def receive_from_worker(self, number):
        print(str(number))

    def sendtotask(self):
        self.set_text_signal.emit("Task: Configured")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    loop = QEventLoop(app)
    asyncio.set_event_loop(loop)
    ui = Window()
    ui.show()
    with loop:
        loop.run_forever()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM