进程同步
进程的数据是独立存在的,进程也能加锁。
from multiprocessing import Process, Lock def f(l,i): l.acquire() print('hello world',i) l.release() if __name__ =='__main__': lock = Lock() #获得锁的实例 for i in range(10): Process(target=f,args=(lock,i)).start() #启动进程,并且把锁的实例传到进程
运行结果
hello world 0 hello world 2 hello world 1 hello world 3 hello world 6 hello world 7 hello world 8 hello world 4 hello world 5 hello world 9
进程为什么要加锁?
因为进程的数据是独立存在的,并不会共享同一块数据。但是有些资源是共享的,比如显示器。如果每个进程都要输出内容,那么显示的就很乱了,这个锁就是在某个进程独自输出的时候独占,不会被其它进程干扰。
进程池
apply 同步执行 串行
apply_async 异步执行 并行
from multiprocessing import Process, Pool,freeze_support import time import os def Foo(i): time.sleep(2) print('当前进程',os.getpid()) return i + 100 def Bar(arg): print("-->exec done:",arg) if __name__ =='__main__': freeze_support() pool = Pool(processes=5) #允许进程池中同时放入5个进程 for i in range(10): #pool.apply_async(func=Foo,args=(i,),callback=Bar) pool.apply(func=Foo,args=(i,)) print('end') pool.close() pool.join() #进程池中进程执行完毕后在关闭,如果注释,那么程序直接关闭。.join()
运行结果
当前进程 5816 #sleep 2s 打印 当前进程 8124 #sleep 2s 打印 当前进程 6488 #sleep 2s 打印 当前进程 5356 当前进程 7036 当前进程 5816 当前进程 8124 当前进程 6488 当前进程 5356 当前进程 7036 end
以上是同步执行,程序显示的效果是串行化执行。
并行化
from multiprocessing import Process, Pool,freeze_support import time import os def Foo(i): time.sleep(2) print('当前进程',os.getpid()) return i + 100 def Bar(arg): print("-->exec done:",arg) if __name__ =='__main__': freeze_support() pool = Pool(processes=5) #允许进程池中同时放入5个进程 for i in range(10): pool.apply_async(func=Foo,args=(i,),callback=Bar) #pool.apply(func=Foo,args=(i,)) print('end') pool.close() pool.join() #进程池中进程执行完毕后在关闭,如果注释,那么程序直接关闭。.join()
运行结果
end 当前进程 6060 #一次打印5个 当前进程 6952 -->exec done: 100 -->exec done: 101 当前进程 3388 -->exec done: 102 当前进程 1600 -->exec done: 103 当前进程 7648 -->exec done: 104 当前进程 6060 当前进程 6952 -->exec done: 105 -->exec done: 106 当前进程 3388 -->exec done: 107 当前进程 1600 -->exec done: 108 当前进程 7648 -->exec done: 109
callback() 回调函数,子进程执行完func,之后在调用的函数。 那么这个函数是子进程调用的还是主进程调用的?
from multiprocessing import Process, Pool,freeze_support import time import os def Foo(i): time.sleep(2) print('当前进程',os.getpid()) return i + 100 def Bar(arg): print("-->exec done:",arg,os.getpid()) #显示调用当前函数的进程id if __name__ =='__main__': freeze_support() pool = Pool(processes=5) #允许进程池中同时放入5个进程 print("主进程",os.getpid()) #显示主进程id for i in range(10): pool.apply_async(func=Foo,args=(i,),callback=Bar) #pool.apply(func=Foo,args=(i,)) print('end') pool.close() pool.join() #进程池中进程执行完毕后在关闭,如果注释,那么程序直接关闭。.join()
运行结果
主进程 7052 end 当前进程 7992 当前进程 1848 -->exec done: 101 7052 -->exec done: 100 7052 当前进程 2212 -->exec done: 102 7052 当前进程 980 当前进程 8064 -->exec done: 103 7052 -->exec done: 104 7052 当前进程 7992 -->exec done: 105 7052 当前进程 1848 -->exec done: 106 7052 当前进程 2212 -->exec done: 107 7052 当前进程 8064 当前进程 980 -->exec done: 109 7052 -->exec done: 108 7052
这里可以看到是主进程调用的回调,这些写的优点是,比如子进程做了数据备份要写到数据库,如果每个子进程都在执行的函数里面写,那么每个进程都要连接一次数据库,用主进程调用的方式就是可以省去这么多的连接数据库的操作。效率更高。