import multiprocessing
# list with global scope
result = [100,200]
def square_list(mylist):
"""
function to square a given list
"""
global result
# append squares of mylist to global list result
for num in mylist:
result.append(num * num)
# print global list result
print("Result(in process p1): {}".format(result))
if __name__ == "__main__":
# input list
mylist = [1,2,3,4]
# creating new process
p1 = multiprocessing.Process(target=square_list, args=(mylist,))
# starting process
p1.start()
# wait until process is finished
p1.join()
# print global result list
print("Result(in main program): {}".format(result))
这里,全局变量 result
可以被新进程中运行的函数访问。既然新进程有自己的python解释器和自己的内存空间,那么如何从父进程访问全局变量呢?
注意:我了解队列/管道/管理器/数组/值的概念。这个问题是专门问子进程如何从父进程读取全局变量的?
答案 0 :(得分:1)
正如我在对您的问题的评论中提到的,您应该使用一个托管列表,该列表作为附加参数传递给 square_list
:
import multiprocessing
def square_list(result, mylist):
"""
function to square a given list
"""
# append squares of mylist to global list result
for num in mylist:
result.append(num * num)
# print global list result
print("Result(in process p1): {}".format(result))
if __name__ == "__main__":
# input list
mylist = [1,2,3,4]
result = multiprocessing.Manager().list([100,200])
# creating new process
p1 = multiprocessing.Process(target=square_list, args=(result, mylist))
# starting process
p1.start()
# wait until process is finished
p1.join()
# print global result list
print("Result(in main program): {}".format(result))
打印:
Result(in process p1): [100, 200, 1, 4, 9, 16]
Result(in main program): [100, 200, 1, 4, 9, 16]
注意事项
如果您的子进程(“子进程”)只读取 result
列表,那么您的代码就可以了。但是当您想要更新列表并将其反映回主进程时,事情会变得有点复杂。
子进程可以通过两种方式更新由主进程创建的对象(我最终会解决对象实际上是全局变量的问题):
让我们以使用全局变量更新简单共享内存对象的情况为例。为此,我将使用一个简单的 multiprocessing.Value
实例来创建一个共享整数:
import multiprocessing
v = multiprocessing.Value('i', 1) # initialize to 1
def worker():
v.value += 10
if __name__ == "__main__":
p = multiprocessing.Process(target=worker)
p.start()
p.join()
print(v.value)
在 Windows 上,这会打印为 1
而不是您所期望的 11
。这是因为在 Windows 上,新进程是使用 spawn
方法创建的。这意味着创建了一个新的空地址空间,启动了一个新的 Python 解释器,并从顶部重新执行源代码,并且执行全局范围内的任何代码,除了 if __name__ == "__main__":
块内的代码,因为在新创建的进程 __name__
不会是 "__main__"
(这是一件好事,否则你会进入递归循环,重新创建新的子进程)。
但这意味着子进程刚刚创建了它自己的全局变量 v
实例。因此,要使其正常工作,v
不能是全局的,必须作为参数传递给 worker
。
但是,如果您使用多处理池,则有一种方法。这个工具允许你用一个特殊的池初始化函数来初始化池中的每个进程:
import multiprocessing
# initialize each process (there is only 1) in the pool
def init_pool(shared_v):
global v
v = shared_v # v is global
def worker():
v.value += 10
if __name__ == "__main__":
v = multiprocessing.Value('i', 1) # I am global
# create pool of size 1:
pool = multiprocessing.Pool(1, initializer=init_pool, initargs=(v,))
pool.apply(worker)
打印:
11
不幸的是,使用可用的共享内存数据类型实现列表需要一些工作。这就是我推荐使用托管列表的原因:
import multiprocessing
# initialize each process (there is only 1) in the pool
def init_pool(shared_result):
global result
result = shared_result # result is global
def square_list(mylist):
"""
function to square a given list
"""
# append squares of mylist to global list result
for num in mylist:
result.append(num * num)
# print global list result
print("Result(in process p1): {}".format(result))
if __name__ == "__main__":
# input list
mylist = [1,2,3,4]
result = multiprocessing.Manager().list([100,200])
pool = multiprocessing.Pool(1, initializer=init_pool, initargs=(result,))
pool.apply(square_list, args=(mylist,))
# print global result list
print("Result(in main program): {}".format(result))
Result(in process p1): [100, 200, 1, 4, 9, 16]
Result(in main program): [100, 200, 1, 4, 9, 16]
此技术适用于 Windows、Linux 等,即所有平台。
将可更新的全局变量移动到 if __name__ == '__main__':
块内(它们仍然是主进程的全局变量)并使用池初始化函数用这些变量初始化池进程。事实上,对于使用 spawn
的平台,您应该考虑将所有不需要的全局定义移到 if __name__ == '__main__':
块内,这些定义不是子进程需要的,而且创建起来很昂贵。
答案 1 :(得分:0)
进程与线程的关键租户之一是它们不共享内存。有一些东西实际上可以共享内存,但一般来说,对于进程,您应该通过队列、管道等传递消息。
以下是通过队列将返回值传回父级的示例:
import multiprocessing
# list with global scope
result = [100,200] #result is re-created on import here in the child process
def square_list(mylist, ret_q):
"""
function to square a given list
"""
global result
# append squares of mylist to global list result
for num in mylist:
result.append(num * num)
# print global list result
print("Result(in process p1): {}".format(result))
ret_q.put(result) #send the modified result to the main process
if __name__ == "__main__":
# input list
mylist = [1,2,3,4]
#return queue
ret_q = multiprocessing.Queue()
# creating new process
p1 = multiprocessing.Process(target=square_list, args=(mylist, ret_q))
# starting process
p1.start()
# wait for the result
result = ret_q.get()
# wait until process is finished
p1.join()
# print global result list
print("Result(in main program): {}".format(result))