ForkingPickler(file, protocol).dump(obj) TypeError: cannot pickle '_tkinter.tkapp' object

旧巷老猫 提交于 2021-01-29 09:12:47

问题


Below is my code my function receives data blocks from the server and puts them in a FIFO buffer after which two functions are called in parallel,

recvData() #to keep receiving data blocks from the server and put in the FIFO buffer
calculate_threshold() #to remove data blocks from the FIFO buffer and perform some calculation, give a real time display on the GUI, and write the result in the file

Code


import socket
import turtle
#import timeit
import queue
import multiprocessing
from tkinter import *

class GUI:

    def __init__(self, master):
        self.master = master
        master.title("Collision Detection")
    
        self.buff_data = queue.Queue()

        self.p1 = multiprocessing.Process(target = self.recvData)
        self.p1 = multiprocessing.Process(target=self.calculate_threshold)
    
        self.input_label = Label(root, text = "Input all the gratings set straight wavelength values in nm")
        self.input_label.grid(row = 0)
    
        self.core_string = "Core "
        self.entries = []

        self.label_col_inc = 0
        self.entry_col_inc = 1
        self.core_range = range(1, 5)

        for y in self.core_range:
            self.core_text = self.core_string + str(y) + '_' + '25'
            self.core_label = Label(root, text = self.core_text)
            self.entry = Entry(root)
            self.core_label.grid(row=1, column=self.label_col_inc, sticky=E)
            self.entry.grid(row=1, column=self.entry_col_inc)
            self.entries.append(self.entry)
            self.label_col_inc += 2
            self.entry_col_inc += 2
    
        self.threshold_label = Label(root, text = "Threshold in nm")
        self.entry_threshold = Entry(root)

        self.threshold_label.grid(row = 2, sticky = E)
        self.entry_threshold.grid(row = 2, column = 1)
    
        self.light_label = Label(root, text = 'Status')
        self.light_label.grid(row = 3, column = 3)

        self.canvas = Canvas(root, width = 150, height = 50)
        self.canvas.grid(row = 4, column = 3)
    
        # Green light
        self.green_light = turtle.RawTurtle(self.canvas)
        self.green_light.shape('circle')
        self.green_light.color('grey')
        self.green_light.penup()
        self.green_light.goto(0,0)

        # Red light
        self.red_light = turtle.RawTurtle(self.canvas)
        self.red_light.shape('circle')
        self.red_light.color('grey')
        self.red_light.penup()
        self.red_light.goto(40,0)
    
        self.data_button = Button(root, text = "Get data above threshold", command = self.getData)
        self.data_button.grid(row = 5, column = 0)


# function to receive TCP data blocks
    def getData(self):
        host = '127.0.0.1'
        port = 5000
        s = socket.socket()
        s.connect((host, port))

        len_message = s.recv(4)
        bytes_length = int(len_message.decode('utf-8'))  # for the self-made server
        recvd_data = s.recv(bytes_length)
        self.buff_data.put(recvd_data)
        self.p1.start()
        self.p2.start()

        self.p1.join()
        self.p2.join()

        
    def recvData(self):
        len_message = s.recv(4)
        while len_message:
            bytes_length = int(len_message.decode('utf-8'))  # for the self-made server
            recvd_data = s.recv(bytes_length)
            self.buff_data.put(recvd_data)
            len_message = s.recv(4)

        else:
            print('out of loop')
        s.close()


    def calculate_threshold(self):
        rmv_data = self.buff_data.get()
        stringdata = rmv_data.decode('utf-8')
        rep_str = stringdata.replace(",", ".")
        splitstr = rep_str.split()

        # received wavelength values
        inc = 34
        wav_threshold = []
        for y in self.entries:
            straight_wav = float(y.get())
            wav = float(splitstr[inc])
            wav_diff = wav - straight_wav
            if wav_diff < 0:
                wav_diff = wav_diff * (-1)
            wav_threshold.append(wav_diff)
            inc += 56

        threshold = float(self.entry_threshold.get())

        # writing into the file
        data = []
        inc1 = 0
        col1 = 2
        col2 = 6

        data.insert(0, (str(splitstr[0])))
        data.insert(1, (str(splitstr[1])))

        for x in wav_threshold:
            if (x > threshold):
                self.red_light.color('red')
                self.green_light.color('grey')
                data.insert(col1, (str(splitstr[34 + inc1])))
                data.insert(col2,(str(x)))
            else:
                self.red_light.color('grey')
                self.green_light.color('green')
                data.insert(col1,'-')
                data.insert(col2,'-')
            inc1 += 56
            col1 += 1
            col2 += 1

        self.write_file(data)



# function to write into the file
    def write_file(self,data):
        with open("Output.txt", "a") as text_file:
            text_file.write('\t'.join(data[0:]))
            text_file.write('\n')

if __name__ == '__main__':
    root = Tk()
    gui = GUI(root)
    root.mainloop()

But I get the following error:


Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
  File "C:/Users/PycharmProjects/GUI/GUI_v4.py", line 88, in getData
    self.p1.start()
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\process.py", line 121, in start
    self._popen = self._Popen(self)
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\context.py", line 224, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\context.py", line 326, in _Popen
    return Popen(process_obj)
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__
    reduction.dump(process_obj, to_child)
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\reduction.py", line 60, in dump
    ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle '_tkinter.tkapp' object
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\spawn.py", line 116, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\multiprocessing\spawn.py", line 126, in _main
    self = reduction.pickle.load(from_parent)
EOFError: Ran out of input

Can someone tell where exactly am I going wrong here?


回答1:


The error is telling you that you can't use multiprocessing for an object that includes tkinter widgets. You're trying to use self.recvData in a separate process. That requires that self be pickled so that it can be sent to the other process. However, python can't do it because it contains tkinter widgets which cannot be pickled.

You will need to move the code which runs in another process to a separate class that does not contain any tkinter widgets.




回答2:


Code changed after creating a new class:

import socket
import turtle
# import timeit
import queue
import multiprocessing
from tkinter import *


class GUI:

    def __init__(self, master):
        self.master = master
        master.title("Collision Detection")

        self.input_label = Label(root, text="Input all the gratings set straight wavelength values in nm")
        self.input_label.grid(row=0)

        self.core_string = "Core "
        self.entries = []


        self.label_col_inc = 0
        self.entry_col_inc = 1
        self.core_range = range(1, 5)

        for y in self.core_range:
            self.core_text = self.core_string + str(y) + '_' + '25'
            self.core_label = Label(root, text=self.core_text)
            self.entry = Entry(root)
            self.core_label.grid(row=1, column=self.label_col_inc, sticky=E)
            self.entry.grid(row=1, column=self.entry_col_inc)
            self.entries.append(self.entry)
            self.label_col_inc += 2
            self.entry_col_inc += 2

        self.threshold_label = Label(root, text="Threshold in nm")
        self.entry_threshold = Entry(root)

        self.threshold_label.grid(row=2, sticky=E)
        self.entry_threshold.grid(row=2, column=1)

        self.light_label = Label(root, text='Status')
        self.light_label.grid(row=3, column=3)

        self.canvas = Canvas(root, width=150, height=50)
        self.canvas.grid(row=4, column=3)

        # Green light
        self.green_light = turtle.RawTurtle(self.canvas)
        self.green_light.shape('circle')
        self.green_light.color('grey')
        self.green_light.penup()
        self.green_light.goto(0, 0)

        # Red light
        self.red_light = turtle.RawTurtle(self.canvas)
        self.red_light.shape('circle')
        self.red_light.color('grey')
        self.red_light.penup()
        self.red_light.goto(40, 0)

        self.data_button = Button(root, text="Get data above threshold", command=recv_data.getData)
        self.data_button.grid(row=5, column=0)


class recv_data:
    def __init__(self):
        self.buff_data = queue.Queue()
        self.p1 = multiprocessing.Process(target=self.recvData)
        self.p1 = multiprocessing.Process(target=self.calculate_threshold)
        self.host = '127.0.0.1'
        self.port = 5002
        self.s = socket.socket()
        self.s.connect((self.host, self.port))

    # function to receive TCP data blocks
    def getData(self):
        len_message = self.s.recv(4)
        bytes_length = int(len_message.decode('utf-8'))  # for the self-made server
        recvd_data = self.s.recv(bytes_length)
        self.buff_data.put(recvd_data)
        self.p1.start()
        self.p2.start()

        self.p1.join()
        self.p2.join()

    def recvData(self):
        len_message = self.s.recv(4)
        while len_message:
            bytes_length = int(len_message.decode('utf-8'))  # for the self-made server
            recvd_data = self.s.recv(bytes_length)
            self.buff_data.put(recvd_data)
            len_message = self.s.recv(4)

        else:
            print('out of loop')
        self.s.close()

    def calculate_threshold(self):
        rmv_data = self.buff_data.get()
        stringdata = rmv_data.decode('utf-8')
        rep_str = stringdata.replace(",", ".")
        splitstr = rep_str.split()

        # received wavelength values
        inc = 34
        wav_threshold = []
        for y in gui.entries:
            straight_wav = float(y.get())
            wav = float(splitstr[inc])
            wav_diff = wav - straight_wav
            if wav_diff < 0:
                wav_diff = wav_diff * (-1)
            wav_threshold.append(wav_diff)
            inc += 56

        threshold = float(gui.entry_threshold.get())

        # writing into the file
        data = []
        inc1 = 0
        col1 = 2
        col2 = 6

        data.insert(0, (str(splitstr[0])))
        data.insert(1, (str(splitstr[1])))

        for x in wav_threshold:
            if (x > threshold):
                gui.red_light.color('red')
                gui.green_light.color('grey')
                data.insert(col1, (str(splitstr[34 + inc1])))
                data.insert(col2, (str(x)))
            else:
                gui.red_light.color('grey')
                gui.green_light.color('green')
                data.insert(col1, '-')
                data.insert(col2, '-')
            inc1 += 56
            col1 += 1
            col2 += 1

        self.write_file(data)

        # function to write into the file

    def write_file(self, data):
        with open("Output.txt", "a") as text_file:
            text_file.write('\t'.join(data[0:]))
            text_file.write('\n')

if __name__ == '__main__':
    root = Tk()
    gui1 = GUI(root)
    rec_data = recv_data()
    root.mainloop()

Error that I get:


Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
TypeError: getData() missing 1 required positional argument: 'self'



来源:https://stackoverflow.com/questions/62811594/forkingpicklerfile-protocol-dumpobj-typeerror-cannot-pickle-tkinter-tkap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!