如果多个进程抢占去对某一个共同的对象的操作的时候,为了防止操作产生冲突,这个时候就可以通过锁的操作来避免。
案例展示
以下展示没有使用锁的案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import time from multiprocessing import Process,Value,Array
def test_func(n,): n.value = n.value + 1
if __name__ == "__main__": num = Value('i',0) for i in range(20): p = Process(target=test_func,args=(num,)) p.start()
time.sleep(1) print(num.value)
|
当改变time.sleep()的时间,就会发现每一次打印的结果都不一样,是因为多个进程在操作同一个对象的原因,在实际的工作当中,多个进程操作同一个对象是非常危险的时候,很有可能导致数据错乱或者数据不同步的情况发生。但是有两种情况列外,就是在操作队列与管道的时候,这两种数据结构由于自身的性质,只能排队被操作,因此不用担心可能出现的错误。
想要保证操作对象时候数据不会被其他进程串改,需要保证在一个进程操作的时候,其他进程不能够访问该对象,即当前进程锁住该对象。操作如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| from multiprocessing import Process from multiprocessing import Lock
def for_fun(lock): lock.acquire() pass lock.release()
if __name__ == '__main__': lock = Lock() p = Process(target=for_fun(), args=(lock, ))
|
进程池
为什么要有进程池的概念?
在实际的需求当中,往往需要创建多个进程,但是进程也不能够随意创建,进程太多不方便管理的同时还会降低效率,因此诞生了进程池,进程池这个对象维护了一个进程管理器,在这个进程池当中,进程是恒定的,被事先设置过。进程池会稳定维护四个进程,并且当任务传递过来后,进程池会接纳所有任务并且让任务等待也存在于进程池当中,不会因为进程不够用而阻塞程序的正常运行。
1 2 3 4 5 6 7 8 9 10 11 12 13
| import time from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
def task(num): print("执行",num) time.sleep(2)
if __name__ == "__main__": pool = ProcessPoolExecutor(4) for ele in range(10): pool.submit(task,ele)
|
在进程池当中,进程都被进程池管理,如果想要进程在执行完毕后再做其他操作可以使用回调函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| """进程池 回调函数 回调函数会把任务函数的结果作为参数执行""" from multiprocessing import Pool import time import os def work(): time.sleep(1) print("%d 进程 work" % os.getpid()) return time.time() def call(res): print("处理回调结果:{}".format(str(res))) if __name__ == '__main__': pool = Pool(2) for i in range(5): res = pool.apply_async(func=work, callback=call) pool.close() pool.join() print("main end")
|
注意:如果进程池当中要使用进程锁。则需要基于Manager钟的Lock和RLock来实现。
这篇写得草率了,唉!