#python #multithreading #user-interface #multiprocessing
Вопрос:
Я разработал графический интерфейс, который позволяет выполнять какое-то преобразование данных.
Каждое преобразование использует другой набор файлов и выполняется совершенно независимо от других задач. Чтобы приложение не зависало при выполнении задачи, я использовал модуль потоковой передачи, чтобы каждая операция выполнялась в отдельном потоке. Я не хочу ускорять вычисления с помощью многопоточности, мне просто нужно адаптивное приложение. Код, который у меня есть, действительно длинный (более 600 строк), поэтому я буду публиковать только соответствующие фрагменты кода, но могут возникнуть некоторые несоответствия из-за удаления больших разделов кода.
import time
from threading import Thread
import tkinter as tk
from tkinter import Tk, ttk
retinaFileName = None
retinaProgBar = None
threadStatus = {'active_threads': [],
'manager': True,
'compile': False,
'retina': False,
'left_hemi':False,
'right_hemi':False}
class layerGenerator:
def __init__(self):
pass
def pack(self, thread):
kernel = 0
time.sleep(0.5)
while kernel < 200 and threadStatus[thread]:
time.sleep(0.01)
kernel =1
print("Done!")
def threadManager():
while threadStatus['manager']:
[t.join() for t in threadStatus['active_threads'] if not t.is_alive()]
threadStatus['active_threads'] = [t for t in threadStatus['active_threads'] if t.is_alive()]
time.sleep(0.1)
print("Exiting manager")
def generateArrays(generator, btn, entry, progBar, cmd, thread):
generator.pack(thread)
threadStatus[thread] = False
btn.config(text="Generate arrays", command=cmd)
def generateRet():
t = Thread(target=generateArrays, args=(retina_generator, button6, retinaFileName, retinaProgBar, generateRet, 'retina'))
t.start()
threadStatus['retina'] = True
threadStatus['active_threads'].append(t)
button6.config(text="Abort", command=abortRet)
def abortRet():
threadStatus['retina'] = False
button6.config(text="Generate arrays", command=generateRet)
def on_closing():
threadStatus['manager'] = False
root.destroy()
retina_generator = layerGenerator()
root = Tk()
root.lift()
root.title("Retina Generator")
root.geometry('640x480')
root.resizable(False, False)
button6 = ttk.Button(root,text="Generate arrays", command=generateRet)
button6.pack()
manager = Thread(target=threadManager)
manager.start()
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
если вы запустите этот код, все кажется очень отзывчивым, но в моем реальном приложении кнопка прерывания обычно регистрируется как нажатая после завершения всего вычисления, что не очень полезно (я предполагаю, что процессор посвящает все свои тактовые циклы функции pack, которая является основной вычислительно дорогостоящей функцией. Только когда это будет сделано, он проверяет другие потоки, и в этот момент операция «прерывается»). Решит ли мультиобработка эту проблему? если да, то как я могу сообщить о событиях завершения, аналогичных while kernel < 200 and threadStatus[thread]
линия? насколько мне известно, разные процессы работают с разными копиями памяти.
Опять же, я подчеркиваю: меня не волнует ускорение одной конкретной функции, скорее возможность запускать и отменять множество операций, сохраняя при этом гибкость пользовательского интерфейса.
P. S: Я подтвердил, что это просто проблема с циклами процессора, так как даже добавление очень небольшой задержки в цикл вычислений (например, печать ядра или даже time.sleep(0,001)) снова делает кнопку «прервать» отзывчивой, но я не хочу намеренно замедлять основные вычисления без причины.