Задать вопрос
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. Но пока попытки тщетны.

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

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

Похожие вопросы