多进程multiprocessing
1
#coding:utf-8
import time
import random
import os
from multiprocessing import Process
def down(text):
print(f'{text}开始下载.....子进程id:{os.getpid()}')
down_time = random.randint(2,5)
time.sleep(down_time)
print(f'{text}下载成功,耗时{down_time}秒......')
def main():
print(f'这里是主进程,{os.getpid()}')
start_time = time.time()
t1 = Process(target=down,args=('中国历史', ))
t2 = Process(target=down,args=('世界历史', ))
t1.start()
t2.start()
end_time = time.time()
print(f'任务下载完成,共耗时{end_time - start_time}秒')
if __name__ == '__main__':
main()
2
#coding:utf-8 import time import random import os from multiprocessing import Process def down(text): print(f'{text}开始下载.....子进程id:{os.getpid()}') down_time = random.randint(2,5) time.sleep(down_time) print(f'{text}下载成功,耗时{down_time}秒......') def main(): print(f'这里是主进程,{os.getpid()}') start_time = time.time() t1 = Process(target=down,args=('中国历史', )) t2 = Process(target=down,args=('世界历史', )) t1.start() t2.start() t1.join() t2.join() end_time = time.time() print(f'任务下载完成,共耗时{end_time - start_time}秒') if __name__ == '__main__': main()
3
#coding:utf-8 import time import random import os from multiprocessing import Process def down(text): print(f'{text}开始下载.....子进程id:{os.getpid()}') down_time = random.randint(2,5) time.sleep(down_time) print(f'{text}下载成功,耗时{down_time}秒......') def main(): print(f'这里是主进程,{os.getpid()}') start_time = time.time() t1 = Process(target=down,args=('中国历史', )) t2 = Process(target=down,args=('世界历史', )) t1.daemon = True t2.daemon t1.start() t2.start() end_time = time.time() print(f'任务下载完成,共耗时{end_time - start_time}秒') if __name__ == '__main__': main()
4
import os import threading import multiprocessing print('Main:',os.getpid()) def worker(sign,lock): lock.acquire() print(sign,os.getpid()) lock.release() record = [] lock = threading.Lock() record = [] lock = multiprocessing.Lock() if __name__ == '__main__': for i in range(5): thread = threading.Thread(target=worker,args=('thread',lock)) thread.start() record.append(thread) for thread in record: thread.join() for i in range(5): process = multiprocessing.Process(target=worker,args=('process',lock)) process.start() record.append(process) for process in record: process.join()
5
正如我们在Linux多线程中介绍的管道PIPE和消息队列message queue,multiprocessing包中有Pipe类和Queue类来分别支持这两种IPC机制。Pipe和Queue可以用来传送常见的对象。
Pipe可以是单向(half-duplex),也可以是双向(duplex)。我们通过mutiprocessing.Pipe(duplex=False)创建单向管道 (默认为双向)。一个进程从PIPE一端输入对象,然后被PIPE另一端的进程接收,单向管道只允许管道一端的进程输入,而双向管道则允许从两端输入。
import multiprocessing as mul def proc1(pipe): pipe.send('hello') print('proc1 rec:',pipe.recv()) def proc2(pipe): print('proc2 rec:',pipe.recv()) pipe.send('hello,too') pipe = mul.Pipe() if __name__ == '__main__': p1 = mul.Process(target=proc1,args=(pipe[0],)) p2 = mul.Process(target=proc2,args=(pipe[1],)) p1.start() p2.start() p1.join() p2.join()
6
这里的Pipe是双向的。
Pipe对象建立的时候,返回一个含有两个元素的表,每个元素代表Pipe的一端(Connection对象)。我们对Pipe的某一端调用send()方法来传送对象,在另一端使用recv()来接收。
Queue与Pipe相类似,都是先进先出的结构。但Queue允许多个进程放入,多个进程从队列取出对象。Queue使用mutiprocessing.Queue(maxsize)创建,maxsize表示队列中可以存放对象的最大数量。
import os import multiprocessing import time def inputQ(queue): info = str(os.getpid()) + '(put):' + str(time.time()) queue.put(info) def outputQ(queue,lock): info = queue.get() lock.acquire() print(str(os.getpid()) + ' get: ' + info) lock.release() record1 = [] record2 = [] lock = multiprocessing.Lock() queue = multiprocessing.Queue(3) if __name__ == '__main__': for i in range(10): process = multiprocessing.Process(target=inputQ,args=(queue,)) process.start() record1.append(process) for i in range(10): process = multiprocessing.Process(target=outputQ,args=(queue,lock)) process.start() record2.append(process) for p in record1: p.join() queue.close() for p in record2: p.join() 7
进程池 (Process Pool)可以创建多个进程。这些进程就像是随时待命的士兵,准备执行任务(程序)。一个进程池中可以容纳多个待命的进程。
import multiprocessing as mul def f(x): return x ** 2 if __name__ == '__main__': pool = mul.Pool(5) rel = pool.map(f,[1,2,3,4,5,6,7,8,9,10]) print(rel)
我们创建了一个容许5个进程的进程池 (Process Pool) 。Pool运行的每个进程都执行f()函数。我们利用map()方法,将f()函数作用到表的每个元素上。这与built-in的map()函数类似,只是这里用5个进程并行处理。如果进程运行结束后,还有需要处理的元素,那么的进程会被用于重新运行f()函数。除了map()方法外,Pool还有下面的常用方法。
apply_async(func,args) 从进程池中取出一个进程执行func,args为func的参数。它将返回一个AsyncResult的对象,你可以对该对象调用get()方法以获得结果。
close() 进程池不再创建新的进程
join() wait进程池中的全部进程。必须对Pool先调用close()方法才能join。
8
import multiprocessing def func1(a,arr): a.value = 3.14 for i in range(len(arr)): arr[i] = 0 a.value = 0 if __name__ == '__main__': num = multiprocessing.Value('d',1.0) arr = multiprocessing.Array('i',range(10)) p = multiprocessing.Process(target=func1,args=(num,arr)) p.start() p.join() print(num.value) print(arr[:])
这里我们实际上只有主进程和Process对象代表的进程。我们在主进程的内存空间中创建共享的内存,也就是Value和Array两个对象。对象Value被设置成为双精度数(d), 并初始化为1.0。而Array则类似于C中的数组,有固定的类型(i, 也就是整数)。在Process进程中,我们修改了Value和Array对象。回到主程序,打印出结果,主程序也看到了两个对象的改变,说明资源确实在两个进程之间共享。
9
import time import random from multiprocessing import Process class DownTask(Process): def __init__(self,text): super().__init__() self.text = text def run(self): print(f'{self.text}开始下载...') down_time = random.randint(2,5) time.sleep(down_time) print(f'{self.text}下载成功,耗时{down_time}秒....') def main(): start = time.time() t1 = DownTask('中国历史') t1.start() t2 = DownTask('世界历史') t2.start() # t1.join() # t2.join() end = time.time() print('总共耗费了%.2f秒.' % (end - start)) if __name__ == '__main__': main()
10
使用进程池Pool创建进程
Pool进程池,可以把进程池比做一个水池,假设我们要完成放满10个水盆水的任务,在这个水池中,最多可以放三个水盆,也就是最多能用三个水盆接水。
Pool有2种启动方式,
1. apply_async() 非阻塞方式(并行,异步),见下,下面代码创建了一个3个进程的进程池,在执行10个任务时,每次都是同时三个进程启动执行三个任务。回到放水任务,相当于有三个水笼头,三个水盆同时接水,每个水盆接满了就将水倒进桶里再重新接水。一直接满10个水盆的水。这三个水盆是同时接水的,并行,异步,互不干涉。
import os import time from multiprocessing import Pool def task(name): print(f'子进程{os.getpid()},执行task:{name}') time.sleep(5) def main(): print(f'父进程{os.getpid()}.') p = Pool(3) for i in range(10): p.apply_async(task,args=(i,)) print('等待所有子进程结束') p.close() p.join() print('所有子进程结束') if __name__ == '__main__': main()
11
apply(),阻塞式,进程池里的进程按顺序执行,必须一个进程执行完了才能继续下一个进程。回到放水任务,相当于有三个水盆,但是只有一个水笼头能用,三个水盆按顺序排好,一个接满了才能放另一个进去,轮流接水,一般不用这个方法来启动,失去了多进程的作用。
import os import time from multiprocessing import Pool def task(name): print(f'子进程{os.getpid()},执行task:{name}') time.sleep(5) def main(): print(f'父进程{os.getpid()}.') p = Pool(3) for i in range(10): p.apply(task,args=(i,)) print('等待所有子进程结束') p.close() p.join() print('所有子进程结束') if __name__ == '__main__': main()
close(), 关闭Pool, 不再接受新的任务。即整个池子不再使用,已运行的进程会继续运行完。
terminate(), 不管任务是否完成,彻底终止任务,相当直接杀死进程,不管是运行的还是没运行的,所有进程all die!
参考
(100条消息) python多进程multiprocessing使用,看这篇就够了(二)_Neil.chen的博客-CSDN博客