set env var in Python multiprocessing.Process
environment-variables, multiprocessing, python
Solution
Yes, that's the right way to do it. While the child will inherit its initial environment from the parent, subsequent changes to `os.environ` made in the child will not affect the parent, and vice-versa:
import os
import multiprocessing
def myfunc(q):
print "child: " + os.environ['FOO']
os.environ['FOO'] = "child_set"
print "child new: " + os.environ['FOO']
q.put(None)
q.get()
print "child new2: " + os.environ['FOO']
if __name__ == "__main__":
os.environ['FOO'] = 'parent_set'
q = multiprocessing.Queue()
proc = multiprocessing.Process(target=myfunc, args=(q,))
proc.start()
q.get()
print "parent: " + os.environ['FOO']
os.environ['FOO'] = "parent_set_again"
q.put(None)
Output:
child start: parent_set
child after changing: child_set
parent after child changing: parent_set
child after parent changing: child_set
If you need to pass an initial environment to the child, you would just pass it in the `args` or `kwargs` list:
def myfunc(env=None):
time.sleep(3)
if env is not None:
os.environ = env
print os.environ['FOO']
if __name__ == "__main__":
child_env = os.environ.copy()
for i in range(3):
child_env['FOO'] = "foo%s" % (i,)
proc = multiprocessing.Process(target=myfunc, kwargs ={'env' : child_env})
proc.start()
Output:
foo0
foo1
foo2
Note that if you're using a `multiprocessing.Pool`, you can use the `initializer`/`initargs` keyword arguments to just set the correct environment once at the start of each process in the pool:
def init(env):
os.environ = env
def myfunc():
print os.environ['FOO']
if __name__ == "__main__":
child_env = os.environ.copy()
child_env['FOO'] = "foo"
pool = multiprocessing.Pool(initializer=init, initargs=(child_env,))
pool.apply(myfunc,())
Output:
foo
Problem
In the subprocess Python 2 module, Popen can be given an `env`. Seems that the equivalent way to do it with Process in multiprocessing module is to pass the `env` dictionnary in `args` or `kwargs`, and then use `os.environ['FOO'] = value` in the `target`. Is it the right way? Is it safe? I mean, no risk that the environment in the parent process or other child processes can be modified? Here is an example (that works). ``` import multiprocessing import time import os def target(someid): os.environ['FOO'] = "foo%i" % someid for i in range(10): print "Job %i: " % someid, os.environ['FOO'] time.sleep(1) if __name__ == '__main__': processes = [] os.environ['FOO'] = 'foo' for someid in range(3): p = multiprocessing.Process(target=target, args=(someid,)) p.start() processes.append(p) for i in range(10): print "Parent: ", os.environ['FOO'] time.sleep(1) for p in processes: p.join() ```