Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何限制多处理过程的范围?_Python_Multiprocessing - Fatal编程技术网

Python 如何限制多处理过程的范围?

Python 如何限制多处理过程的范围?,python,multiprocessing,Python,Multiprocessing,使用python模块,以下精心设计的示例以最少的内存需求运行: import multiprocessing # completely_unrelated_array = range(2**25) def foo(x): for x in xrange(2**28):pass print x**2 P = multiprocessing.Pool() for x in range(8): multiprocessing.Process(target=foo, ar

使用python模块,以下精心设计的示例以最少的内存需求运行:

import multiprocessing 
# completely_unrelated_array = range(2**25)

def foo(x):
    for x in xrange(2**28):pass
    print x**2

P = multiprocessing.Pool()

for x in range(8):
    multiprocessing.Process(target=foo, args=(x,)).start()
取消对
完全不相关数组的创建的注释,您将发现每个派生的进程为
完全不相关数组的副本分配内存!这是一个我不知道如何解决的更大项目的最小示例;多处理似乎可以复制所有全局的东西。我不需要共享内存对象,我只需要传入
x
,然后处理它而不需要整个程序的内存开销


旁白:有趣的是
print id(完全不相关的数组)
inside
foo
中的
print id给出了相同的值,这表明不知何故这可能不是拷贝…

因为
os.fork()的性质,
\uuuuu main\uuuu
模块的全局命名空间中的任何变量都将由子进程继承(假设您在Posix平台上),因此您将看到子进程中的内存使用情况在创建后立即反映出来。我不确定是否所有的内存都被分配了,但据我所知,内存是共享的,直到你真的尝试在子内存中更改它,在这一点上创建了一个新的副本。另一方面,Windows不使用
os.fork()
——它在每个子系统中重新导入主模块,并pickle您想要发送给子系统的任何局部变量。因此,使用Windows,您实际上可以通过仅在
if\uuuuuuu name\uuuuuu==“\uuuuuu main\uuuu”:
保护中定义它来避免在子进程中复制大型全局文件,因为该保护中的所有内容都将仅在父进程中运行:

import time
import multiprocessing 


def foo(x):
    for x in range(2**28):pass
    print(x**2)

if __name__ == "__main__":
    completely_unrelated_array = list(range(2**25)) # This will only be defined in the parent on Windows
    P = multiprocessing.Pool()

    for x in range(8):
        multiprocessing.Process(target=foo, args=(x,)).start()
现在,在Python2.x中,如果使用Posix平台,则只能通过分叉创建新的
多处理.Process
对象。但是在Python3.4上,可以通过使用上下文指定如何创建新进程。因此,我们可以指定Windows用于创建新进程的上下文,并使用相同的技巧:

# Note that this is Python 3.4+ only
import time
import multiprocessing 

def foo(x):
    for x in range(2**28):pass
    print(x**2)


if __name__ == "__main__":
    completely_unrelated_array = list(range(2**23))  # Again, this only exists in the parent
    ctx = multiprocessing.get_context("spawn") # Use process spawning instead of fork
    P = ctx.Pool()

    for x in range(8):
        ctx.Process(target=foo, args=(x,)).start()
如果您需要2.x支持,或者希望继续使用
os.fork()
创建新的
Process
对象,我认为要降低报告的内存使用率,最好的方法是立即删除子对象中有问题的对象:

import time
import multiprocessing 
import gc

def foo(x):
    init()
    for x in range(2**28):pass
    print(x**2)

def init():
    global completely_unrelated_array
    completely_unrelated_array = None
    del completely_unrelated_array
    gc.collect()

if __name__ == "__main__":
    completely_unrelated_array = list(range(2**23))
    P = multiprocessing.Pool(initializer=init)

    for x in range(8):
        multiprocessing.Process(target=foo, args=(x,)).start()
    time.sleep(100)

这里最重要的是你要瞄准哪个平台。 Unix系统进程是使用写时复制(cow)内存创建的。因此,即使每个进程都获得了父进程的完整内存的副本,但在修改时,该内存实际上只按每页基数(4KB)分配。 因此,如果你只针对这些平台,你不必做任何改变

如果您的目标平台没有cow forks,您可能希望使用python 3.4及其新的forking上下文
spawn
forkserver
,请参阅 这些方法将创建与父进程不共享任何或有限状态的新进程,并且所有内存传递都是显式的

但这并不是说生成的进程将导入您的模块,以便显式复制所有全局数据,并且不可能在写入时进行复制。为了防止这种情况,您必须缩小数据的范围

import multiprocessing  as mp
import numpy as np

def foo(x):
    import time
    time.sleep(60)

if __name__ == "__main__":
    mp.set_start_method('spawn')
    # not global so forks will not have this allocated due to the spawn method
    # if the method would be fork the children would still have this memory allocated
    # but it could be copy-on-write
    completely_unrelated_array = np.ones((5000, 10000))
    P = mp.Pool()
    for x in range(3):
        mp.Process(target=foo, args=(x,)).start()
e、 g带spawn的top输出:

%MEM     TIME+ COMMAND
29.2   0:00.52 python3                                                
0.5   0:00.00 python3    
0.5   0:00.00 python3    
0.5   0:00.00 python3    
用叉子:

%MEM     TIME+ COMMAND
29.2   0:00.52 python3                                                
29.1   0:00.00 python3    
29.1   0:00.00 python3                                                
29.1   0:00.00 python3

请注意它是如何超过100%,这是由于写时复制

您针对的是什么版本的Python,您使用的是什么平台?@dano Python 2.7.6,尽管我想知道多处理是否在3中发生了变化。
多处理
在Python 3.3中发生了相当大的变化,通过引入。我要说的是,将所有子进程中不希望发生的任何事情都计算到它们自己的模块中,对吗?i、 e.将
foo
放在它自己的模块中,然后导入它。@dano如果你给我看一个解决这个问题的python 3示例,它将对我有用(将来可能还有其他人!)。谢谢你的回答!如果我理解正确,您的2.x方法仍然会产生复制的开销,对吗?我认为是时候开始考虑Python3了……@与
os.fork()
挂钩,对象实际上不会复制到子进程中,除非您对它们进行写入。在此之前,内存在父级和分叉子级之间共享。不过请注意,孩子们可以在封面下写入继承的对象。@Hooked实际上,最好不要尝试删除全局变量,因为
全局完全无关的数组
可能会导致对象的增量。在孩子们身上一点也不要碰他们。