簡體   English   中英

如何在 Pyqt5 中使用 multiprocessing.Queue 和 pyqtgraph?

[英]How to use multiprocessing.Queue in Pyqt5 with pyqtgraph?

我正在使用 pygtgraph 和 pyqt5 用十字准線繪制線條,然后根據算法在十個不同的 colors 中對它們進行着色。 我還使用 slider 來選擇要着色的第一行數。 每次 slider 值發生變化時,GUI 都會凍結以計算 colors,這是我不想發生的。

我試圖將計算放在不同的線程中,它有點工作,但現在我想使用進程。 我想要做的是使用多處理來創建一個線程池來處理隊列中的算法調用和一個線程來重新着色繪制的線條。

self.threads = max(1, multiprocessing.cpu_count() - 3)
self.queue_in = multiprocessing.Queue()
self.queue_out = multiprocessing.Queue()

self.the_pool = multiprocessing.Pool(self.threads, algorithm_worker, (self.queue_in, self.queue_out))
self.recolor_thread = multiprocessing.Process(target=assign_and_recolor_worker, args=(
        self.queue_out, self.color_numbers, self.canvas.getPlotItem(), self.pens))
self.recolor_thread.start()

這些是功能:

def algorithm_worker(queue_in, queue_out):
    print(os.getpid(), "working")
    while True:
        lines = queue_in.get(block=True)
        result = list(get_color_nums_algo(lines)) if lines else []
        print(result)
        queue_out.put(result)


def assign_and_recolor_worker(queue_in, color_nums, plot_item, pens):
    print(os.getpid(), "working")
    while True:
        color_nums = queue_in.get(block=True)
        for plotdataitem, pen_i in zip(plot_item.items, color_nums):
            plotdataitem.setPen(pens[pen_i % len(pens)])

第一部分似乎工作正常,但由於我是多處理新手,所以我在第二部分中遇到了很多困難。

  1. 我不知道如何從self.recolor_thread中更改主 window 中的變量,主要是:分配的顏色編號列表self.color_numbers
  2. 我也不知道如何訪問self.canvas.getPlotItem().items

1 - 我嘗試使用管理器,但它沒有更新值

self.manager = multiprocessing.Manager()
self.color_numbers = self.manager.list()

2 - 我通過了 PlotItem 和 mkPen 但得到了類似的錯誤

TypeError: cannot pickle 'PlotItem' object

我該如何解決或規避這些問題? 這是必要代碼https://pastebin.com/RyvNpP67的鏈接

首先,您需要保持 GUI 事件循環運行。 GUI 運行一個事件循環,當您長時間停留在事件/信號中時,該循環會凍結/掛起。 如果您單擊按鈕並停留在按鈕單擊信號中,則當您處於 function 時,GUI 將無法處理其他事件。

如果線程正在等待 I/O 或 time.sleep 被調用,線程只會對此有所幫助。 I/O 是當您調用諸如 socket.recv() 或 queue.get() 之類的東西時。 這些操作等待數據。 當線程等待數據時,主線程可以運行並處理 Qt 事件循環上的事件。 只運行計算的線程不會讓主線程處理事件。

多處理用於將數據發送到單獨的進程並等待結果。 在等待結果時,如果等待是在單獨的線程中,您的 Qt 事件循環可以處理事件。 將數據發送到單獨的進程並從該進程接收數據可能需要很長時間。 除此之外,有些項目不能輕易地發送到單獨的進程。 可以將 QT GUI 項發送到單獨的進程,但這很困難,並且可能必須在操作系統中使用 window 句柄。

多處理

def __init__(self):
    ...

    self.queue_in = multiprocessing.Queue()
    self.queue_out = multiprocessing.Queue()

    # Create thread that waits for data and plots the data
    self.recolor_thread = threading.Thread(target=assign_and_recolor_worker, args=(
        self.queue_out, self.color_numbers, self.canvas.getPlotItem(), self.pens))
    self.recolor_thread.start()  # comment this line

    self.alg_proc = multiprocessing.Process(target=algorithm_worker, args=(self.queue_in, self.queue_out))
    self.alg_proc.start()

def calc_color(self):
    lines_to_recog = self.current_lines[:self.color_first_n]
    self.queue_in.put(lines_to_recog)  # Send to process to calculate

處理事件

如果你只想要一個響應式的 GUI 調用 QtWidgets.QApplication.processEvents()。 盡管並不總是推薦使用“processEvents”,但它在某些情況下可能非常有用。

def get_color_nums_algo(lines: list, proc_events=None) -> list:
    li = []
    for _ in lines:
        li.append(np.random.randint(0, 10))
        try:
            proc_events()
        except (TypeError, Exception):
            pass
    return li

class MainWindow(QtWidgets.QMainWindow):
    ....

    def calc_color(self):
        lines_to_recog = self.current_lines[:self.color_first_n]

        # Color alg
        proc_events= QtWidgets.QApplication.processEvents
        color_nums = list(get_color_nums_algo(lines_to_recog, proc_events)) if lines_to_recog else []

        # Plot data
        for plotdataitem, pen_i in zip(self.canvas.getPlotItem().items, color_nums):
            plotdataitem.setPen(self.pens[pen_i % len(self.pens)])
            QtWidgets.QApplication.processEvents()

鼠標移動

mouseMoved 事件也可以非常快地發生。 如果update_drawing花費的時間太長,您可能需要使用計時器定期調用update_drawing ,因此當可能發生 10 個事件時調用 1 次。

暫無
暫無

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

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