1

所以我遇到了一个非常奇怪的错误。我正在为一个非常基本的 TCP 服务器制作一个基本的小 GUI,但是当我生成该进程时,它返回以下回溯:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
    return self.func(*args)
  File "C:\Users\username\Desktop\localssh\serverv2.py", line 48, in start_server
    process.start()
  File "C:\Python27\lib\multiprocessing\process.py", line 130, in start
    self._popen = Popen(self)
  File "C:\Python27\lib\multiprocessing\forking.py", line 271, in __init__
    dump(process_obj, to_child, HIGHEST_PROTOCOL)
  File "C:\Python27\lib\multiprocessing\forking.py", line 193, in dump
    ForkingPickler(file, protocol).dump(obj)
  File "C:\Python27\lib\pickle.py", line 224, in dump
    self.save(obj)
  File "C:\Python27\lib\pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Python27\lib\pickle.py", line 419, in save_reduce
    save(state)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\multiprocessing\forking.py", line 66, in dispatcher
    self.save_reduce(obj=obj, *rv)
  File "C:\Python27\lib\pickle.py", line 401, in save_reduce
    save(args)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 548, in save_tuple
    save(element)
  File "C:\Python27\lib\pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Python27\lib\pickle.py", line 419, in save_reduce
    save(state)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 725, in save_inst
    save(stuff)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 725, in save_inst
    save(stuff)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 725, in save_inst
    save(stuff)
  File "C:\Python27\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python27\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python27\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python27\lib\pickle.py", line 313, in save
    (t.__name__, obj))
PicklingError: Can't pickle 'tkapp' object: <tkapp object at 0x02A4C4F0>

我的代码如下:

import SocketServer
import multiprocessing
from Tkinter import *

class MyTCPHandler(SocketServer.BaseRequestHandler):
    """
    The RequestHandler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print "{} wrote:".format(self.client_address[0])+str(self.data)
        #print self.data
        # just send back the same data, but upper-cased
        self.request.sendall(self.data.upper())



class Application(object):
    def __init__(self):
        self.root=Tk()
        self.root.resizable(FALSE,FALSE)
        self.root.geometry('500x500')
        self.root.title("Server GUI")
    def set_widgets(self):
        self.start_server_button=Button(self.root,text="Start Server",command=self.start_server)
        self.end_server_button=Button(self.root,text="Stop Server",command=self.stop_server)
        self.logger=Text(self.root,width=50)
    def grid_widgets(self):
        self.start_server_button.grid(row=1,column=0)
        self.end_server_button.grid(row=2,column=0)
        self.logger.grid(row=0,column=0)
    def configure(self):
        pass
    def run(self):
        self.set_widgets()
        self.grid_widgets()
        self.configure()
        self.root.mainloop()
    def start_server(self):
        self.logger.insert(END,"Starting process for client.")
        process=multiprocessing.Process(target=self.start_serving)
        process.start()
    def start_serving(self):
        HOST, PORT = "localhost", 9999
        self.server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
        self.server.serve_forever()
    def stop_server(self):
        self.server.shutdown()
if __name__ == "__main__":
    Application().run()
4

3 回答 3

1

我不完全确定这是否会解决您的问题,但是,另一个 stackoverflow 问题可能有您正在寻找的答案。看来您需要将该__getstate__()方法添加到Application类中。

于 2012-06-23T05:14:09.247 回答
1

PicklingError: Can't pickle 'tkapp' object: <tkapp object at 0x02A4C4F0>看起来您可能正在尝试将对象共享/发送到子流程,尽管隐含地,基本上multiprocessing默认情况下模块遵循no share方法,这意味着所有对象都被复制并发送到子流程,目标是更容易和更安全true的多线程系统,但以牺牲性能为代价。

Python 使用该pickle模块来序列化对象,因此,如果你不能序列化它,你就不能将它发送到子进程,还有第二个要求,该函数必须是可导入的,即:

def start_server(self):
    self.logger.insert(END,"Starting process for client.")
    process=multiprocessing.Process(target=self.start_serving)
    process.start()

是一个成员函数,它实际上是不可导入的,多处理试图序列化它的所有成员变量,其中大部分无法序列化,尽管这是一种预感。

你可以试试这个,放在课外。

def start_serving():
    HOST, PORT = "localhost", 9999
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
    server.serve_forever()

假设您不需要任何进程间通信,如果需要,您可以使用多处理模块中的队列。

这就是您启动子流程的方式。

 def start_server(self):
    self.logger.insert(END,"Starting process for client.")
    self.process = multiprocessing.Process(target=start_serving) # make sure you keep a reference of the process.
    self.process.start()

然后你可以杀死子进程。

def stop_server(self):
    self.process.terminate()


if __name__ == "__main__":
    Application().run()

尽管我建议您使用ThreadingMixIn而不是手动创建子进程,但由于 GIL 而进程执行,我不确定它是否使用threadprocess实际上thread并未在多核机器上运行。我已经测试过了,不幸的是你不能杀死子进程,serve_forever似乎正在阻塞......

于 2012-06-23T05:22:26.590 回答
1

我遇到了同样的问题:

p=multiprocessing.Process(target=self.targetMethod)

我将其更改为:

p=multiprocessing.Process(target=self.targetMethod())

我不再收到 EOF 错误。我不明白这里到底发生了什么。为时已晚,但希望它对某人有所帮助。

于 2015-09-09T09:04:48.597 回答