Danhui Xu
Danhui Xu

Reputation: 69

Why my multiprocessing pool is not working? Python

here is my code:

# -*- coding:utf-8 -*-
import time
import tkinter as tk
from multiprocessing import Pool


class Application(tk.Tk):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.title('test')
        self.geometry('300x500')
        self.main_ui()
        self.pool = Pool(10)

    def a(self, word):
        print(word, ' start')
        time.sleep(5)
        print(word, 'end')

    def call_a(self, word):
        self.pool.apply_async(self.a, (word,))

    def main_ui(self):
        bnt1 = tk.Button(self, text='a', command=lambda: self.call_a('a'))
        bnt1.place(x=0, y=0, height=100, width=70)
        bnt1 = tk.Button(self, text='b', command=lambda: self.call_a('b'))
        bnt1.place(x=0, y=100, height=100, width=70)
        # pass


def main():
    app = Application()
    app.mainloop()


if __name__ == '__main__':
    main()

l would like let print(word, ' start') and print(word, ' start') in other processing without blocking process of tkinter, because time.sleep(5) with block process of tkinter. As i think that two process won;t be enough, so i use a processing pool.but the program does not work this time(when i push button, def a(self,word) do not work).

the gui can show correctly, but when i push the button, def a(self, word): is not working, i don't why and how to fix the problem.

By the way, i'm using python3.

Thank you

Upvotes: 0

Views: 737

Answers (1)

larsks
larsks

Reputation: 311328

You cannot ignore the return value of multiprocessing.Pool.apply_async. It's not designed as a fire-and-forget mechanism for running "background" tasks. If you modify your code to check the result:

    def call_a(self, word):
        res = self.pool.apply_async(self.a, (word,))
        ret = res.get()
        print("return value:", ret)

What you will see when you click on the a button is:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib64/python3.10/tkinter/__init__.py", line 1921, in __call__
    return self.func(*args)
  File "/home/lars/tmp/python/gui.py", line 25, in <lambda>
    bnt1 = tk.Button(self, text="a", command=lambda: self.call_a("a"))
.
.
.
TypeError: cannot pickle '_tkinter.tkapp' object

So, the problem is that your call to apply_async is failing with an exception, but you were never retrieving it. The failure is caused by the fact that apply_async attempts to pickle objects in order to send them to the worker, but that's not possible with a Tk application object.

To make your code work probably requires a some re-architecture: for example, rather than trying to use multiprocessing.Pool, consider manually spawning a number of processes (or threads!), and then using a queue to pass data to the workers.

Upvotes: 2

Related Questions