多进程
按书面语来解释进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
多线程无法利用多核的优势,python提供了mutiprocessing.
multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
import os
print(os.cup_count()) # 查看cpu的核心数
linux下可以使用fork开启新进程
import os
print('Process (%s) start...' % os.getpid())
pid = os.fork() #开启新进程
if pid==0:
print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
os._exit(1)
else:
print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
一个fork()属于系统调用,它比较特殊。调用一次,返回两次,因为操作系统自动把当前进程和子进程进行返回。子进程永远返回0,而父进程返回子进程的ID。
multiprocessing模块
创建一个进程时,只需要传入一个执行函数和函数的参数,创建一个
Process实例,用start()方法启动,这样创建进程比fork()还要简单。
join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同
步。
process语法结构
Process([group [, target [, name [, args [, kwargs]]]]])
参数 | 作用 |
---|---|
target | 表示这个进程实例所调用的对象 |
args | 表示调用对象的位置参数元组 |
kwargs | 表示调用对象的关键字参数字典 |
name | 为当前进程实例的别名 |
group | 在多数情况下用不到 |
process类常见函数
函数 | 功能 |
---|---|
is_alive() | 判断进程实例是否还在执行 |
join([timeout]) | 是否等待进程实例执行结束,或等待多少秒 |
start() | 启动进程实例(创建子进程) |
run() | 如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法 |
terminate() | 不管任务是否完成,立即终止 |
编程练习
#coding=utf-8
from multiprocessing import Process
import os
from time import sleep
#子进程要执行的函数
def run_proc(name,age,**kwargs):
for i in range(10):
print('子进程执行中,name = %s, age = %d, pid = %d'%(name, age, os.getpid())
print(kwargs)
sleep(0.5)
if __name__ == "__main__":
print('父进程 %d'%os.getpid())
p = Process(target=run_proc,args=('xiaoming',18),kwargs={'xiaohua':19})
print('子进程将要执行')
#启动子进程
p.start()
#等待一秒之后
sleep(1)
#立即结束
p.terminate() #立即关闭进程
#join()⽅法可以等待⼦进程结束后再继续往下运⾏,通常⽤于进程间的同步。
p.join()
print('子进程已结束')结果:
进程运行完成后会自动退出
进程池
开多进程的目的是为了并发,如果有多核,通常有几个核就开几个进程,进程开启过多,效率反而会下降(开启进程是需要占用系统资源的,而且开启多余核数目的进程也无法做到并行),但很明显需要并发执行的任务要远大于核数,这时我们就可以通过维护一个进程池来控制进程数目,比如httpd的进程模式,规定最小进程数和最大进程数…
在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。
**Pool([numprocess [,initializer [, initargs]]]):创建进程池 **
参数 | 作用 |
---|---|
numprocess | 要创建的进程数,如果省略,将默认使用cpu_count()的值 |
initializer | 是每个工作进程启动时要执行的可调用对象,默认为None |
initargs | 是要传给initializer的参数组 |
函数介绍
函数 | 作用 |
---|---|
apply_async(func[, args[, kwds[, callback]]]) | 它是非阻塞 |
apply(func[, args[, kwds]]) | 是阻塞的 |
close() | 关闭pool,使其不在接受新的任务 |
terminate() | 结束工作进程,不在处理未完成的任务 |
join() | 主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用 |
编程练习
import multiprocessing
import time
def func(msg):
print "msg:", msg
time.sleep(3)
print "end"
if __name__ == "__main__":
pool = multiprocessing.Pool(processes = 3)
for i in xrange(4):
msg = "hello %d" %(i)
pool.apply_async(func, (msg, )) #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去 这个是非阻塞的
print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"
pool.close()
pool.join() #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
print "Sub-process(es) done."
import multiprocessing
import time
def func(msg):
print "msg:", msg
time.sleep(3)
print "end"
return "done" + msg
if __name__ == "__main__":
pool = multiprocessing.Pool(processes=4)
result = []
for i in xrange(3):
msg = "hello %d" %(i)
result.append(pool.apply_async(func, (msg, )))
pool.close()
pool.join()
for res in result:
print ":::", res.get() #得出每个返回结果的值
print "Sub-process(es) done."