进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。里面包含对各种资源的调用,内存的管理,网络接口的调用等。对各种资源管理的集合 就可以称为 进程 。每个进程至少有一个线程,称为主线程。
在linux系统下可以用fork()很方便的创建进程,window下没有fork函数,但可以用multiprocessing包很好的使用进程。
创建进程的语法和线程差不多
'''
使用multiprocessing的Process创建子进程
'''
from multiprocessing import Process
import os
#子进程执行函数
def run_proc(name):
print 'Run child process %s (%s)' % (name,os.getpid())
print 'It parent pid is {}'.format(os.getppid())
if __name__ == '__main__':
print 'Parent process {}'.format(os.getpid())
p1 = Process(target=run_proc, args=('p1',)) #创建一个子进程
print 'Child1 process will start.'
#p1.daemon = True #守护进程
p1.start() #启动子进程
p1.join() #等待p1结束,再继续运行主进程
print 'Child1 process end.'
p2 = Process(target=run_proc, args=('p2',)) #创建另一个子进程
print 'Child2 process will start...'
p2.start()
p2.join()
print 'Child2 process end.'
*注意:
os.getppid()获取父进程pid
os.getpid()获取当前进程pid
进程Queue:进程间的通信(数据传递)
'''
进程间的通信
'''
from multiprocessing import Queue, Process
import os,time,random
def write(q):
print 'Process to write {}'.format(os.getpid())
for x in ['A','B','C']:
print 'Put {} to queue...'.format(x)
q.put(x)
time.sleep(random.random())
print
def read(q):
print 'Process to read {}'.format(os.getpid())
while True:
value = q.get()
print 'Get {} from queue'.format(value)
if __name__ == '__main__':
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
pw.start()
pr.start()
pw.join()
pr.terminate() #立刻终止pr进程
进程Manager:真正实现进程间的数据共享(不只是数据传递)
一个multiprocessing.Manager对象会控制一个服务器进程,其他进程可以通过代理的方式来访问这个服务器进程。( 好比一个全局变量,所有函数都可以访问,存取,修改..)
# 实现了进程之间的数据共享
from multiprocessing import Process, Manager
import os
def f(d,l):
d["name"] = "Time"
d["sex"] = "Man"
d["age"] = 20
l.append(os.getpid())
print(l)
if __name__ == "__main__":
with Manager() as manager:
d = manager.dict() # 生成一个字典,可以在多个进程直接共享和传递
l = manager.list(range(5)) # 生成一个列表,可以在多个进程直接共享和传递
res = []
for i in range(10):
p = Process(target=f,args=(d,l))
p.start()
res.append(p)
for j in res: # 等待结果
j.join()
print(d)
print(l)
进程池Pool
进程池内部维护一个进程序列。当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:
- apply(串行)
- apply_async(并行)
#! /usr/bin/env python3
# -*- coding:utf-8 -*-
from multiprocessing import Pool
import os,time
def Foo(i):
time.sleep(2)
print("in process",os.getpid())
return i + 100
def Bar(arg):
print("-->exec done:",arg,os.getpid())
if __name__ == "__main__":
pool = Pool(4) # 我的电脑是4核,默认是cpu核数,即同时最多运行进程的数目
print("主进程:",os.getpid())
for i in range(10):
pool.apply_async(func=Foo,args=(1,),callback=Bar) # callback = 回调
# 这里回调的函数是主进程去回调的(生产中若所有进程完毕后将结果写入数据库,只需要写个回调就行了,不必每个进程中写入数据库)
# pool.apply(func=Foo,args=(1,)) # 串行,主进程会被阻塞直到函数执行结束(不建议使用)
# pool.apply_async(func=Foo,args=(1,)) # 并行
print("end")
pool.close() #关闭进程池(pool),不再接受新的任务。
pool.join() #wait进程池中的全部进程。必须对Pool先调用close()方法才能join
多进程模式最大的优点就是稳定性高,因为一个子进程崩溃了,不会影响主进程和其他子进程。(当然主进程挂了所有进程就全挂了,但是Master进程只负责分配任务,挂掉的概率低)著名的Apache最早就是采用多进程模式。
多进程模式的缺点是创建进程的代价大,在Unix/Linux系统下,用fork调用还行,在Windows下创建进程开销巨大。另外,操作系统能同时运行的进程数也是有限的,在内存和CPU的限制下,如果有几千个进程同时运行,操作系统连调度都会成问题。
多线程模式通常比多进程快一点,但是也快不到哪去,而且,多线程模式致命的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃,因为所有线程共享进程的内存。在Windows上,如果一个线程执行的代码出了问题,你经常可以看到这样的提示:“该程序执行了非法操作,即将关闭”,其实往往是某个线程出了问题,但是操作系统会强制结束整个进程。