目录
进程创建
创建进程实现在python下的并发,同时调用多个cpu来操作线程
方法一:
from multiprocessing import Process
import time
def f(name):
time.sleep(1)
print('hello', name,time.ctime())
if __name__ == '__main__':
p_list=[]
for i in range(3): #开启三个进程,此时是使用3个cpu,每个cpu分别执行一个
p = Process(target=f, args=('alvin',))
p_list.append(p)
p.start()
for i in p_list:
i.join()
print('end')
方法二:通过继承
from multiprocessing import Process
import time
class MyProcess(Process):
# def __init__(self):
# super(MyProcess, self).__init__()
# #self.name = name
def run(self):
time.sleep(1)
print ('hello', self.name,time.ctime()) #self.name是进程名
if __name__ == '__main__':
p_list=[]
for i in range(3):
p = MyProcess()
# p.daemon=True #设置为守护进程
p.start()
p_list.append(p)
for p in p_list:
p.join() #如果子进程没有执行完,主进程就卡在这里,不往下运行
print('end')
#########################################
hello MyProcess-1 Sat May 4 15:42:00 2019
hello MyProcess-2 Sat May 4 15:42:00 2019
hello MyProcess-3 Sat May 4 15:42:00 2019
end
os.getppid() 显示父进程的id
os.getpid() 显示当前进程的id
p.is_alive() 实例方法,判断进程是否还活着
p.terminate() 直接停止进程运行
进程间通信
进程间通信与线程间通信不同,线程之间共享一块内存,简单的线程间通信只要设置全局变量或者同步对象event(具体看进程篇)就能做到。而进程在不同的两块内存之中。
方案一:使用进程队列来实现进程间通信
import time
import multiprocessing
def foo(q):
time.sleep(1)
print("son process",id(q))
q.put(123) #在子进程中放入值
q.put("chen")
if __name__ == '__main__':
q=multiprocessing.Queue() #创建进程队列
p=multiprocessing.Process(target=foo,args=(q,)) #在进程之间传递进程队列,作为全局变量
p.start()
print("main process",id(q))
print(q.get()) #在主进程中拿出数据
print(q.get())
方案二:使用双向管道来实现经常队列
from multiprocessing import Process, Pipe
def f(conn):
conn.send([12, {"name":"chen"}, 'hello']) #子进程给主进程发送数据
response=conn.recv() #子进程接收主进程发送的数据
print("response",response)
conn.close() #关闭管道
if __name__ == '__main__':
parent_conn, child_conn = Pipe() #创建双向管道
p = Process(target=f, args=(child_conn,))
p.start()
print(parent_conn.recv()) # 主进程接收子进程发送的数据prints "[42, None, 'hello']"
parent_conn.send("儿子你好!") #主进程给子进程发送数据
p.join()
方案二:使用Manager实现进程间通信
Pipe和Queue只是实现了进程间数据的交互,并没有实现进程间数据共享,即一个进程修改另一个进程的数据
Manager支持的类型有list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value和Array。
from multiprocessing import Process, Manager
def f(d, l,n):
d[n] = '1' #{0:"1"}
d['2'] = 2 #{0:"1","2":2}
l.append(n) #[0,1,2,3,4, 0,1,2,3,4,5,6,7,8,9]
if __name__ == '__main__':
with Manager() as manager: #with语法自动close()
d = manager.dict()#通过manager得到一个字典对象
l = manager.list(range(5))#通过manager得到一个列表对象
p_list = []
for i in range(10):
p = Process(target=f, args=(d,l,i)) #将通过manager创建的对象最为参数传入子进程中
p.start()
p_list.append(p)
for res in p_list:
res.join()
print(d)
print(l)
注:进程间的通信是很耗费资源的,因为存在两块不同的内存之中,所以本质上是一个进程将数据拷贝到另一个进程,存在内存的消耗。
进程同步(同步锁)和进程池
在进程与进程之间的数据不共用,但是进程与进程间也有同时使用的系统资源,比如终端和屏幕,在多个进程向显示器输出内容的时候,可能会导致数据混乱的显现,比如:
因此使用进程同步锁来规定同一时刻,只能有一个进程来使用共用资源。
from multiprocessing import Process, Lock
import time
def f(lock, i):
lock.acquire() #请求同步锁
time.sleep(1)
print('hello world ',i)
lock.release() #释放同步锁
if __name__ == '__main__':
lock = Lock() #创建同步锁
for num in range(10):
Process(target=f, args=(lock, num)).start()
进程池
在内存中同时会有很多的进程需要执行,那改怎么去执行这些进程成了问题,如果去同时运行这些进程那就太耗费资源,但是一个一个执行就费时,因此引入进程池,使用一个折中 的办法,在进程池中指定最大执行进程数量,进程的完执行速度有快有慢,当进程池中的某个进程执行完,等待的进程就可以进入进程池执行,直到完成所有进程的执行。
#每一秒执行5个进程
from multiprocessing import Pool
import time
def Foo(i):
time.sleep(1)
print(i)
return "HELLO %s"%i
def Bar(arg):
print(arg)
print("hello")
if __name__ == '__main__':
pool = Pool(5) #定义进程池的最大进程数。如果不指定数目,默认根据电脑的cpu数量
for i in range(100): #开一百个子进程
#开启进程池
pool.apply_async(func=Foo, args=(i,),callback=Bar) #callback指定回调函数(就是某个动作或者函数执行成功后再去执行的函数)
pool.close()
pool.join() # join与close调用顺序是固定的