2017-02-09 65 views
3

此代码执行在Linux上,但抛出一个AttributeError:类型的对象“T”对窗户没有属性“VAL”,为什么呢?Python的多Linux窗口差异

from multiprocessing import Process 
import sys 

class T(): 
    @classmethod 
    def init(cls, val): 
     cls.val = val 

def f(): 
    print(T.val) 

if __name__ == '__main__': 
    T.init(5) 

    f() 

    p = Process(target=f, args=()) 
    p.start() 

回答

2

Windows缺少一个fork()系统调用,它复制当前进程。这有很多含义,包括windows multiprocessing文档页面上列出的含义。更具体地讲:

Bear in mind that if code run in a child process tries to access a global variable, then the value it sees (if any) may not be the same as the value in the parent process at the time that Process.start was called.

在内部,蟒蛇通过从头开始一个新的进程,并告诉它再次加载所有模块创建Windows上的新进程。因此,您在当前流程中所做的任何更改都不会被看到。

在你的榜样,这意味着在子过程中,你的模块将被载入,但if __name__ == '__main__'部分将不会运行。所以T.init将不会被调用,并且T.val将不存在,因此您看到的错误。

在另一方面,在POSIX系统(包括Linux)的,进程创建使用fork和全球所有的状态保持不变。孩子运行一切的副本,所以它不必重新加载任何东西,并会看到它的副本T及其副本val

这也意味着,工艺创作是对POSIX系统资源,更快,更轻,尤其是在“复制”使用写入时复制,以避免实际复制数据的开销。

有使用多处理时其他怪癖,所有这些都在python multiprocessing guidelines详述。

+0

'fork' vs'spawn'是一个很老的辩论。 NT内核一直有能力进行写入时复制分支,但是从MS-DOS出来的Windows API本身不允许它。另外,在分叉多进程的过程中还存在一些不小的问题,在这种情况下,除了“fork”:“forkserver”和“spawn”之外,Python 3.4还为您提供了两个启动选项。后者是Windows上唯一的选择。 – eryksun

+1

确实如此。尽管NT内核中存在底层功能,但我始终发现在Win32中可以使用奇怪的无叉系统调用。我不禁要看到它,因为微软不愿意屈服于旧的*“那些不懂Unix的人被指责重塑它”*说。哎呀,他们等到W2k8才加入符号链接。我准备好打赌,在未来的某些Windows版本中将会出现'fork()'等效,只是给他们一些时间。可能带有一个名称,如'DuplicateCurrentProcess'。 – spectras

+0

我的意思是不允许它是系统从在DOS上运行的Windows 2.0进化而来的方式,不会与'fork'一起工作 - 至少不会用于活动进程。内核模式Windows(win32k.sys)扩展了NT'EPROCESS'和'ETHREAD'结构,使'fork'可能会出现问题,比如死锁。 OTOH,为了分析一个过程,我们确实有能力发出惰性[快照](https://msdn.microsoft.com/en-us/library/dn457825)。 – eryksun