在进程间共享带文件句柄属性的对象

5 投票
1 回答
4960 浏览
提问于 2025-04-15 12:38

我有一个关于进程之间共享资源和文件句柄的问题。这里是我的测试代码:

from multiprocessing import Process,Lock,freeze_support,Queue
import tempfile
#from cStringIO import StringIO

class File():
    def __init__(self):
        self.temp = tempfile.TemporaryFile()
        #print self.temp

    def read(self):
        print "reading!!!"
        s = "huanghao is a good boy !!"
        print >> self.temp,s
        self.temp.seek(0,0)

        f_content = self.temp.read()
        print f_content

class MyProcess(Process):
    def __init__(self,queue,*args,**kwargs):
        Process.__init__(self,*args,**kwargs)
        self.queue = queue

    def run(self):
        print "ready to get the file object"
        self.queue.get().read()
        print "file object got"
        file.read()

if __name__ == "__main__":
    freeze_support()
    queue = Queue()
    file = File()

    queue.put(file)
    print "file just put"

    p = MyProcess(queue)
    p.start()

然后我遇到了一个 KeyError 错误,像下面这样:

file just put
ready to get the file object
Process MyProcess-1:
Traceback (most recent call last):
  File "D:\Python26\lib\multiprocessing\process.py", line 231, in _bootstrap
    self.run()
  File "E:\tmp\mpt.py", line 35, in run
    self.queue.get().read()
  File "D:\Python26\lib\multiprocessing\queues.py", line 91, in get
    res = self._recv()
  File "D:\Python26\lib\tempfile.py", line 375, in __getattr__
    file = self.__dict__['file']
KeyError: 'file'

我认为当我把 File() 对象放进队列时,这个对象被序列化了,而文件句柄是不能被序列化的,所以我得到了 KeyError 错误:

有没有人知道该怎么解决这个问题?如果我想共享带有文件句柄属性的对象,我应该怎么做呢?

1 个回答

7

我必须要反对@Mark反复说的“文件句柄不能在运行中的进程之间传递”这个说法——这在现代的操作系统中根本不成立,比如Unix(包括免费的BSD变种、MacOSX和Linux等等)。当然,sendmsg可以做到这一点(在“Unix套接字”上,使用SCM_RIGHTS标志)。

现在,珍贵的multiprocessing模块完全有理由不利用这个特性(即使假设在Windows上也有黑魔法可以实现它)——大多数开发者无疑会错误使用它(让多个进程同时访问同一个打开的文件,导致竞争条件)。正确的使用方式是,一个拥有打开某些文件独占权限的进程,将打开的文件句柄传递给一个权限较低的进程——然后再也不要自己使用那个句柄。无论如何,在multiprocessing模块中无法强制执行这一点。

回到@Andy最初的问题,除非他只打算在Linux上工作(而且只和本地进程打交道),并且愿意在/proc文件系统上做一些小把戏,否则他需要更明确地定义他的应用需求,并相应地序列化file对象。大多数文件都有路径(或者可以让它们有路径:实际上没有路径的文件非常少,Windows上我相信是不存在的),因此可以通过路径进行序列化——还有很多其他文件足够小,可以通过发送它们的内容来序列化——等等等等。

撰写回答