Nano Hash - криптовалюты, майнинг, программирование

Python TKinter GUI обновляется из нескольких потоков, является ли он потокобезопасным? Некоторый пример кода

Я провел некоторое исследование по этой проблеме, которая возникла у меня с TKinter, который обновляет графический интерфейс на основе данных из других потоков. Как многие предлагали в Интернете, я прибегнул к использованию стратегии опроса очереди с методом self.root.after().

Это работает довольно хорошо, но у меня есть проблема, в которой мне нужно обновить графики matplotlib, встроенные в графический интерфейс TKinter, и это «деактивирует»/отвлекает внимание от/возможно, блокирует другие аспекты графический интерфейс В частности, если я набираю что-то в записи TKinter и обновляется рисунок matplotlib, курсор больше не находится в записи, и мой процесс ввода прерывается.

Чтобы решить эту проблему, я решил попробовать обновить TKinter в отдельном потоке. Я видел в Интернете много людей, которые утверждали, что TKinter не является потокобезопасным, но я также видел других, которые говорили, что он безопасен для потоков. Я пошел дальше и сделал пример программы, которая, кажется, работает довольно хорошо: курсор может оставаться в записи, даже когда график обновляется. Но я хотел бы знать, безопасна ли эта программа? Или он подвержен сбоям, случайным или предсказуемым? Что я могу сделать, чтобы иметь потокобезопасный графический интерфейс?

Вот мой пример кода:

import Tkinter as tk
import threading
import Queue
import datetime
import math
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.gridspec as gridspec

gui_queue = Queue.Queue()

GUI_THEME_COLOR = 'lightblue'

##################################################
class MainGUI:
    def __init__(self, root):
        self.root = root
        self.root.title('TKinter GUI with Threaded Updates')
        self.root.minsize(width=800, height=300)
        self.root.config(background=GUI_THEME_COLOR)

        self.big_frame = tk.Frame(master=root)
        self.big_frame.pack(fill=tk.BOTH, expand=tk.YES, padx=10, pady=10)

        self.button1 = tk.Button(master=self.big_frame, text='Button 1', command=self.button1_command)
        self.button1.grid(row=0, column=0)

        self.entry1 = tk.Entry(master=self.big_frame)
        self.entry1.bind('<Return>', self.entry1_event)
        self.entry1.grid(row=1, column=0)

    def entry1_event(self, event):
        self.button1.config(text=str(self.entry1.get()))
        self.entry1.delete(0, tk.END)

    def button1_command(self):
        print 'Button 1 clicked'


class GUIManipulator(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.app = None
        self.start_time = datetime.datetime.utcnow()
        self.sec_checker = 1
        self.num_loops = 0
        self.x_list = []
        self.y_list = []

    def run(self):
        print 'Starting GUIManipulator thread...'
        while gui_queue.empty():    # Wait here until we receive the MainGUI instance
            pass
        self.app = gui_queue.get()
        while True:
            diff_time = (datetime.datetime.utcnow() - self.start_time).total_seconds()
            floor_diff_time = math.floor(diff_time)
            if floor_diff_time >= self.sec_checker:     # Configure button1 text every second
                self.app.button1.config(text=str(floor_diff_time))
                self.sec_checker += 1
                self.plot_figure()

    def plot_figure(self):
        self.num_loops += 1
        self.x_list.append(self.num_loops)
        self.y_list.append(math.sin(self.num_loops/5.0))

        if self.num_loops == 1:
            self.fig1 = Figure(figsize=(12, 6), facecolor=GUI_THEME_COLOR)
            self.fig1.suptitle('Figure 1',
                                fontsize=14,
                                fontweight='bold')

            self.gs = gridspec.GridSpec(2, 2)

            self.plot1 = self.fig1.add_subplot(self.gs[:, 0])
            self.plot1.set_title('Plot 1')
            self.plot1.set_xlabel('x')
            self.plot1.set_ylabel('sin(x)', labelpad=-10)
            self.plot1.grid(True)

        if self.num_loops > 1:
            self.plot1.cla()
        self.plot1.plot(self.x_list, self.y_list)

        if self.num_loops == 1:
            self.canvas = FigureCanvasTkAgg(self.fig1, master=self.app.big_frame)
            self.canvas.draw()
            self.canvas.get_tk_widget().grid(row=2, column=0)
        else:
            self.canvas.draw()


def main():
    root = tk.Tk()
    app = MainGUI(root)

    gui_queue.put(app)

    gui_manipulator_thread = GUIManipulator()
    gui_manipulator_thread.daemon = True
    gui_manipulator_thread.start()

    root.mainloop()


if __name__ == '__main__':
    main()

Заранее спасибо!



Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..