看multiprocessing部分的Python文档,一点思考:
https://www.rddoc.com/doc/Python/3.6.0/zh/library/multiprocessing/#module-multiprocessing
离职啦,感觉一直拖拖拖,现在反而清醒轻松了不少,开始疯狂产出吧~
from multiprocessing import Process, Lock
def f(l, i):
l.acquire()
try:
print('hello world', i)
finally:
l.release()
if __name__ == '__main__':
lock = Lock()
for num in range(10):
Process(target=f, args=(lock, num)).start()
这里给进程设置了一个进程锁lock。lock在不同进程使用同一共享内存时,能够确保线程之间互不影响,使用lock的方法是, 在每个线程/进程使用共享内存资源或修改共享内存之前,执行lock.acquire()将共享内存上锁, 确保当前进程执行时,内存不会被其他进程访问,执行运算完毕后,使用lock.release()将锁打开, 保证其他的线程可以使用该共享内存。
看似这样做,进程就会输出0-9了,但实际上并不会。
# output result
hello world 0
hello world 1
hello world 5
hello world 2
hello world 4
hello world 7
hello world 3
hello world 6
hello world 8
hello world 9
可见,第一个进程必然是0,这毫无疑问,但后面却散乱排布。这与使用锁的初衷相违背,这是为什么呢?
思考后发现,在第一个进程执行的过程中,即i=0时,它拥有当前的lock,因此它必然是先执行的。但是由于进程是非阻塞的,因此在执行Process的过程中,还是可以继续迭代的,即num=1,2,...,9这个过程中他们都有可能进入Process这一步,等待num=0时执行函数结束,获得当前的Process,因此后面的顺序是不可控的。
如果想要按顺序排布,可以将进程设置为阻塞的。即当前进程执行完之前,后面的进程会先挂起。这可以通过join()函数来实现。
# blocking
from multiprocessing import Process, Lock
def f(l, i):
l.acquire()
try:
print('hello world', i)
finally:
l.release()
if __name__ == '__main__':
lock = Lock()
for num in range(10):
p = Process(target=f, args=(lock, num))
p.start()
p.join()
输出结果为:
# output result
hello world 0
hello world 1
hello world 2
hello world 3
hello world 4
hello world 5
hello world 6
hello world 7
hello world 8
hello world 9