多处理包中process.py
的源代码使用以下模式;请注意Process
,_MainProcess
和_current_process
之间的关系。
class Process(object):
'''
Process objects represent activity that is run in a separate process
The class is analagous to `threading.Thread`
'''
_Popen = None
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
assert group is None, 'group argument must be None for now'
count = _current_process._counter.next()
self._identity = _current_process._identity + (count,)
其中_current_process
稍后定义为:
class _MainProcess(Process):
def __init__(self):
self._identity = ()
self._daemonic = False
self._name = 'MainProcess'
self._parent_pid = None
self._popen = None
self._counter = itertools.count(1)
self._children = set()
self._authkey = AuthenticationString(os.urandom(32))
self._tempdir = None
_current_process = _MainProcess()
del _MainProcess
我不明白的是_current_process
是_MainProcess
类的唯一实例,它是Process
的子类,在其中使用{{1} }}。这对我来说似乎是循环的。
上面的代码在以下示例中进行了简化,该示例运行正常并打印42.
_current_process
答案 0 :(得分:1)
在C / C ++中,您可以使用前向声明获得类似的结果。在Java中,它并非不可能,但你可能需要反思才能让它发挥作用。
这里的事情是从对象调用方法,因此存在变量。它是定义它的子类还是父类是无关紧要的。一切都在运行时完成,所以在此之前不需要num
存在。
使用您的示例:
a = A()
a.print_num()
Traceback (most recent call last):
File "test.py", line 18, in <module>
a.print_num()
File "test.py", line 9, in print_num
print b.num
NameError: global name 'b' is not defined
或者甚至是陌生人(从C ++ / Java的角度来看)版本:
class A(object):
def print_num(self):
print self.num
class B(A):
def __init__(self, num):
self.num = num
b = B(42)
b.print_num()
答案 1 :(得分:0)
_current_process
变量始终设置为当前正在运行的进程的Process
对象。它是全球性的,但它的价值实际上是在几个地方设定的。一个是你最初指出的那个,它发生在模块的顶层:
_current_process = _MainProcess()
del _MainProcess
这意味着当您直接或间接导入process
模块时,_current_process
会自动设置为特殊情况MainProcess
实例,该实例代表一个顶级进程。使用multiprocessing
的脚本。
但是,它也设置在Process._bootstrap
内部,在分叉或生成后立即在新进程内调用:
def _bootstrap(self):
from . import util
global _current_process
try:
...
_current_process = self
...
因此,新创建的Process
设置了_current_process
,而不是MainProcess
实例。
现在,当您在任何给定进程中调用p = Process(...)
时,新创建的Process
实例的属性应基于当前进程'上下文的属性,无论如何那可能。因此:
class Process(object):
...
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
assert group is None, 'group argument must be None for now'
count = _current_process._counter.next()
self._identity = _current_process._identity + (count,)
self._authkey = _current_process._authkey
self._daemonic = _current_process._daemonic
self._tempdir = _current_process._tempdir
这就是为什么如果您有父,子,和孙子Process
个实例,他们的名字是:
家长:<_MainProcess(MainProcess, started)>
儿童:<Process(Process-1, started)>
孙子:<Process(Process-1:1, started)>
孙子的名字是基于孩子的名字,而不是父母的名字。
这种模式在Python中是允许的,因为它使用后期绑定;变量名称和方法直到运行时才绑定到对象。因此,self._authkey = _current_process._authkey
行仅在实际调用Process.__init__
时进行评估,这将始终在导入process.py
后进行评估,这意味着将_current_process
定义。
答案 2 :(得分:0)
这是简化代码的C ++版本。 您需要两个类的前向声明。
class A {
public:
void print_other_class_member();
};
class B:A {
public:
int num;
B();
};
然后声明一个B类的实例,并在A类方法的定义中使用它。
#include <stdio.h>
#include "forward.h"
class B;
B b;
B::B(){
num = 42;
}
void A::print_other_class_member(){
printf("%d\n",b.num);
}
int main(){
A a;
a.print_other_class_member();
}
这在C ++中运行得很好。与Python的唯一区别是你需要一个前向声明。