Python菜鸟编程第十九课之多进程拓展
1.多进程修改全局变量
demo1:
import os
import time
num=0
pid=os.fork()
if pid ==0:
num+=1
print('son jc %s'%num)
else:
time.sleep(1)
num+=1
print('father jc %s'%num)
运行结果:
son jc 1
father jc 1
demo2:
import os
import time
pid = os.fork()
if pid == 0:
print('fork1_1')
else:
print('fork1_2')
pid = os.fork()
if pid == 0:
print('fork2_1')
else:
print('fork2_2')
运行结果:
fork1_2
fork2_2
fork2_1
fork1_1
fork2_2
fork2_1
父子进程执行无规律,完全取决操作系统的调度算法。
1.1multiprocessing.Process相应参数方法
import multiprocessing
print(help(multiprocessing.Process))
Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
参数 | 描述 |
---|---|
group | |
tatget | 表示进程实例所调用的对象 |
args | 表示调用对象位置参数元组 |
kwargs | 表示调用对象的关键字参数字典 |
name | 当前进程实例的别名 |
常用方法:
方法名 | 描述 |
---|---|
is_alive() | 判断进程实例是否正在进行 |
join | 等待进程实例执行结束,或者等待多少秒 |
start() | 启动进程实例(创建子进程) |
run() | 如果未给定target参数,对这个对象调用start()方法时,就执行对象中的run() |
terminate() | 不管任务是否完成,立即终止 |
常用属性
属性名 | 描述 |
---|---|
name | 当前进程的实例名,默认为Progress-N,N从1开始 |
pid | 当前进程实例的pid值 |
demo:
使用类来创建
from multiprocessing import Process
import time
import os
#继承Process类
class Process_Class(Process):
#模块中,Process类本身有__init__方法,现在这个子类重写Process方法
#导致无法完全初始化一个Process类,进而不能从这个类继承的一些方法和属性
#解决方法,将继承类本身传递给Process__init__,完成初始操作。
def __init__(self,interval):
Process.__init__(self)
self.interval = interval
#重写了Process类的run()方法
def run(self):
print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid()))
t_start = time.time()
time.sleep(self.interval)
t_stop = time.time()
print("(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start))
if __name__=="__main__":
t_start = time.time()
print("当前程序进程(%s)"%os.getpid())
p1 = Process_Class(2)
p1.start()
p1.join()
t_stop = time.time()
print("(%s)执行结束,耗时%0.2f"%(os.getpid(),t_stop-t_start))
2.进程池
进程池:子进程数量不多,可以使用Process方法,当数量巨大,如成百上千个,手动创建工作量巨大,可以使用multiprocessing中的Pool方法。
初始化Pool方法时,可以指定一个最大进程数,当有新的请求提交给Pool时,如果池未满,就可以创建一个新的进程来执行请求。假如达到最大值,请求会进行等待,直到有进程结束。
2.1multiprocessing.Process相应参数方法
函数名 | 描述 |
---|---|
apply_async(func[,args[,kwargs]]) | 使用非阻塞方式调用func(并执行,阻塞方式必须等待上一个进程退出才能执行下一进程),args为传递给func的单参数,kwargs为传递给func的关键字参数。 |
apply(func[,args[,kwargs]]) | 使用阻塞方式调用func |
close() | 关闭Pool,使其不再接受新任务 |
terminate() | 不管任务是否完成,立即终止 |
join() | 主线程阻塞,等待主线程退出,一般在close()或者terminate()之后使用 |
3.Queue,进程间的通信
初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头);
Queue.qsize():返回当前队列包含的消息数量
Queue.empty():如果队列为空,返回True,反之False
Queue.full():如果队列满了,返回True,反之False
Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常
2)如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常
Queue.get_nowait():相当Queue.get(False)
Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常
2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常
Queue.put_nowait(item):相当Queue.put(item, False)
demo:
from multiprocessing import Process, Queue
import os
import time
import random
# 写数据进程执行的代码:
def write(q):
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
while True:
if not q.empty():
value = q.get(True)
print('Get %s from queue.' % value)
time.sleep(random.random())
else:
break
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 等待pw结束:
pw.join()
# 启动子进程pr,读取:
pr.start()
pr.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
print('')
print('所有数据都写入并且读完')
运行结果:
demo:
# 1
li = [1, 2, 3, 4]
res = 0
for num in li:
res += num
print(res)
# 2
li = [1, 2, 3, 4]
def reduce_test(array):
res = 0
for num in array:
res += num # 被写死
return res
print(reduce_test(li))
# 3
li = [1, 2, 3, 4]
def multi(x, y):
return x*y
def reduce_test(func, array):
res = 1
# res = array.pop(0)
for num in array:
res=func(res, num)
return res
print(reduce_test(multi, li))
# 24
print(reduce_test(lambda x, y: x*y, li))
# 24
# 4 传递初始值
li = [1, 2, 3, 4]
def multi(x, y):
return x*y
def reduce_test(func, array, init=None):
if init is None:
res = array.pop(0)
else:
res = init
for num in array:
res=func(res, num)
return res
print(reduce_test(multi, li, 100))
print(reduce_test(lambda x, y: x*y, li, 100))
运行结果: