Python - "can't pickle thread.lock" 在 Windows 中的多进程下创建线程时出错

Python - "can't pickle thread.lock" error when creating a thread under a multiprocess in Windows

我被困在我认为是基本的多进程和线程问题上。我已经设置了一个多进程,并且在这个线程中。但是,当我在 init 函数中设置线程 class 时,出现以下错误:

"TypeError: can't pickle thread.lock objects".

但是,如果在 init 函数之外设置线程,则不会发生这种情况。有谁知道为什么会这样?注意我正在使用 Windows.

下面是一些代码来说明这个问题。如下所示,它 运行 没问题。但是,如果从 DoStuff init def 中调用 print_hello(),则会发生错误,如果在多进程 运行() def 中调用,则没关系。

任何人都可以指出正确的方向,以便从 init 调用时 运行 没问题吗?谢谢!

import multiprocessing
import threading
import time

class MyProcess(multiprocessing.Process):

    def __init__(self, **kwargs):
        super(MyProcess, self).__init__(**kwargs)
        self.dostuff = DoStuff()

    def run(self):
        print("starting DoStuff")
        # This works fine if the line below is uncommented and __init__ self.print_hello() is commented...
        self.dostuff.print_hello()


class DoStuff(object):
    def __init__(self, **kwargs):
        super(DoStuff, self).__init__(**kwargs)

        # If the following is uncommented, the error occurs...
        #   Note it also occurs if the lines in start_thead are pasted here...
        # self.print_hello()

    def print_hello(self):
        print "hello"
        self.start_thread()

    def start_thread(self):
        self.my_thread_instance = MyThread()
        self.my_thread_instance.start()
        time.sleep(0.1)


class MyThread(threading.Thread):
    def __init__(self):
        super(MyThread, self).__init__()

    def run(self):
        print("Starting MyThread")


if __name__ == '__main__':
    mp_target = MyProcess()       # Also pass the pipe to transfer data
    # mp_target.daemon = True
    mp_target.start()
    time.sleep(0.1)

看起来没有简单的答案,似乎是Windows的限制(我的情况是Win 7,python 3.6);在 Windows 上,您似乎需要先启动进程,然后才能在拥有的对象中启动工作线程。

Unix (CentOS 7, python 2.7.5) 似乎没有这样的限制。

作为实验,我修改了您的代码如下;此版本检查 OS 并首先启动进程,或首先启动线程:

import multiprocessing
import threading
import time
import os

class MyProcess(multiprocessing.Process):

    def __init__(self, **kwargs):
        super(MyProcess, self).__init__(**kwargs)
        self.dostuff = DoStuff(self)

    def run(self):
        print("MyProcess.run()")
        print("MyProcess.ident = " + repr(self.ident))
        if os.name == 'nt':
            self.dostuff.start_thread()

class DoStuff(object):
    def __init__(self, owner, **kwargs):
        super(DoStuff, self).__init__(**kwargs)
        self.owner = owner
        if os.name != 'nt':
            self.start_thread()

    def start_thread(self):
        print("DoStuff.start_thread()")
        self.my_thread_instance = MyThread(self)
        self.my_thread_instance.start()
        time.sleep(0.1)

class MyThread(threading.Thread):
    def __init__(self, owner):
        super(MyThread, self).__init__()
        self.owner = owner

    def run(self):
        print("MyThread.run()")
        print("MyThread.ident = " + repr(self.ident))
        print("MyThread.owner.owner.ident = " + repr(self.owner.owner.ident))

if __name__ == '__main__':
    mp_target = MyProcess()       # Also pass the pipe to transfer data
    mp_target.daemon = True
    mp_target.start()
    time.sleep(0.1)

... 并在 Windows 上获得以下信息,其中进程首先开始:

MyProcess.run()
MyProcess.ident = 14700
DoStuff.start_thread()
MyThread.run() 
MyThread.ident = 14220
MyThread.owner.owner.ident = 14700

...以及 Linux 上的以下线程首先启动的位置:

DoStuff.start_thread()
MyThread.run()
MyThread.ident = 140316342347520
MyThread.owner.owner.ident = None
MyProcess.run()
MyProcess.ident = 4358

如果是我的代码,我会很想总是先启动进程,然后在该进程中创建线程;以下版本在两个平台上都适合我:

import multiprocessing
import threading
import time

class MyProcess(multiprocessing.Process):

    def __init__(self, **kwargs):
        super(MyProcess, self).__init__(**kwargs)
        self.dostuff = DoStuff()

    def run(self):
        print("MyProcess.run()")
        self.dostuff.start_thread()

class DoStuff(object):
    def __init__(self, **kwargs):
        super(DoStuff, self).__init__(**kwargs)

    def start_thread(self):
        self.my_thread_instance = MyThread()
        self.my_thread_instance.start()
        time.sleep(0.1)

class MyThread(threading.Thread):
    def __init__(self):
        super(MyThread, self).__init__()

    def run(self):
        print("MyThread.run()")

if __name__ == '__main__':
    mp_target = MyProcess()       # Also pass the pipe to transfer data
    mp_target.daemon = True
    mp_target.start()
    time.sleep(0.1)