zvepb
@zvepb

Как использовать multiprocessing в tkinter?

Добрый день могущественный Хабр.

Я использую потоки в таком коде :
Рабочий код окна
import os
import threading
import time

from tkinter import *
import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext


class MainWindow(tk.Frame):
    def __init__(self, root):
        super().__init__(root)
        self.init_main()


    def init_main(self):
        lb_log = Label(text=u"логин ")
        lb_log .pack()
        ent_value_log = Entry(width=40)
        ent_value_log .pack()
        lb_pass = Label(text=u"пароль ")
        lb_pass.pack()
        ent_value_pass = Entry(width=40)
        ent_value_pass.pack()
        btn_print = ttk.Button(text='print', command=lambda: self.printing(ent_value_log.get(), ent_value_pass.get()))
        btn_print .place(x=340, y=20)
        self.console = scrolledtext.ScrolledText(state='disable')
        self.console.pack(pady=15)


    def insert_to_console(self, text):
        self.console.configure(state='normal')  # enable insert
        self.console.insert(END, text)
        self.console.yview(END)  # autoscroll
        self.console.configure(state='disabled')


    def pr(self, login, password):
        self.insert_to_console(login + ' ' + password)
        time.sleep(5)
        self.insert_to_console(login + ' ' + password)
        time.sleep(5)

    def printing(self, login, password):
        pycrypt = threading.Thread(target=self.pr, args=(login, password))
        pycrypt.start()

    def run_app():
        root = tk.Tk()
        app = MainWindow(root)
        root.title("palevo")
        root.geometry("420x400")
        root.mainloop()

if __name__ == "__main__":
        zv = MainWindow
        zv.run_app()


И все работает. Но я понимаю, что для моей программы тут - threading замедляет работу и мне надо использовать процессы. Я курю док 2-ой день и еще не вкурил. Без tkinter я могу поменять
def printing(self, login, password):
        pycrypt = threading.Thread(target=self.pr, args=(login, password))
        pycrypt.start()

на
def printing(self, login, password):
        pycrypt = Process(target=self.pr, args=(login, password))
        pycrypt.start()

и все запускается. И код работает быстрее.

Но с tkinter как только я это делаю получаю исключение :
TypeError: cannot pickle '_tkinter.tkapp' object
EOFError: Ran out of input
на это строке
pycrypt.start()

Помогите разобрать, чего мне не хватает и как это можно запустить. Я так понимаю мне надо использовать очереди или как-то указать что tk.Tk() это главный процесс и связать его с функцией printing.
Так полагаю, что это делает multiprocessing.Pipe и multiprocessing.Queue. Но пока попытки тщетны.

Буду признателен любой помощи.
  • Вопрос задан
  • 789 просмотров
Решения вопроса 1
Vindicar
@Vindicar
RTFM!
Исходи из того, что между процессами лучше передавать только примитивные типы данных и простые коллекции (списки, кортежи, словари). Так что не надо передавать объекты Tkinter как есть, извлеки из них требуемые данные и передавай их.
EDIT:
Идеальный сценарий - использование пары multiprocessing.Queue.
Код дочернего процесса слушает одну очередь, и обрабатывает полученные там задания, а потом пишет в другую ответы.
Код материнского процесса занимается работой с GUI, складывает задания в первую очередь, и время от времени мониторит вторую очередь на предмет новых ответов. Используй root.after() для мониторинга.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы