Unexpected behaviour in python multiprocessing
<p>I'm trying to understand the following odd behavior observed using the <code>python mutiprocessing</code>.</p>

<p>Sample testClass:
    import os
    import multiprocessing    </p>

<pre><code>class testClass(multiprocessing.Process):    

    def __del__(self):
        print "__del__ PID: %d" % os.getpid()
        print self.a    

    def __init__(self):
        multiprocessing.Process.__init__(self)
        print "__init__ PID: %d" % os.getpid()
        self.a = 0    

    def run(self):
        print "method1 PID: %d" % os.getpid()
        self.a = 1
</code></pre>

<p>And a little test program:
    from testClass import testClass    </p>

<pre><code>print "Start"
proc_list = []
proc_list.append(testClass())
proc_list[-1].start()    

proc_list[-1].join()    

print "End"
</code></pre>

<p>This produces:</p>

<pre><code>Start
__init__ PID: 89578
method1 PID: 89585
End
__del__ PID: 89578
0
</code></pre>

<p>Why it does not print <code>1</code>? </p>

<p>I'm guessing that it's related to the fact that <code>run</code> is actually being executed on a different process as can be seen. If this is the expected behavior how is everyone using multiprocessing where processes have an expensive <code>__init__</code> as in processes that need to open a database?</p>

<p>And shouldn't this behaviour be better highlighted in multiprocessing documentation?</p>

<p>When calling <code>start()</code>, the interpreter forks and creates a child process, which gets a copy of the page tables from the parent. These point to pages which are marked as readonly and only copied when written (COW). The interpreter, when executing <code>run</code> in the child process, accesses the child's copy of the <code>PyObject</code> which represents <code>a</code>. The parent's memory is not touched. The child also gets a copy of the file descriptors table, which means that if a connection is opened by the parent, that file descriptor is inherited by the child. You can see (with <code>strace</code>) that the child is created via <code>clone</code> without <code>CLONE_FILES</code>:</p>

<pre><code>clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f460d8929d0)
</code></pre>

<p>Therefore, from clone man page:</p>

<blockquote>
  <p>If CLONE_FILES is not set, the child process inherits a copy of all file descriptors opened in the calling process at the time of clone(). (The duplicated file descriptors in the child refer to the same open file descriptions (see open(2)) as the corresponding file descriptors in the calling process.) Subsequent operations that open or close file descriptors, or change file descriptor flags, performed by either the calling process or the child process do not affect the other process. </p>
</blockquote>

python python-multiprocessing