python 3.x 多进程编程
多进程编程
- 第一种方法:
- 首选使用ProcessPoolExecutor进行多进程编程
- from concurrent.futures import ProcessPoolExecutor, as_completed
- 在ProcessPoolExecutor内部实现还是multiprocessing
- 第二种方法:
- multiprocessing进行多进程编程
- multiprocessing比ProcessPoolExecutor更加底层.
- 只有了解了multiprocessing才能更好的了解ProcessPoolExecutor.
- Process类的方法
- def run(self):
- def start(self):
- def terminate(self): 关闭进程
- def join(self, timeout=None):
- def is_alive(self): 判断进程是否运行.
return False
- multiprocessing中的进程池
- Pool(self, processes=None, initializer=None, initargs=(), maxtasksperchild=None, context=None):
- processes:线程池的数量(多少个进程)
- 如果processes为None,processes会通过os的cpu_count()来声明有多少个cpu,就会有多少个进程,因为对于多进程来说,进程数最好等于cpu的数量,这样性能是最高的,所以说processes的值给不给都可以.
- apply_async()源码:
- def apply_async(self, func, args=(), kwds={}, callback=None, error_callback=None):
if self._state != RUN:
raise ValueError("Pool not running")
result = ApplyResult(self._cache, callback, error_callback)
self._taskqueue.put(([(result._job, 0, func, args, kwds)], None))
return result - ApplyResult类似于Future类
- def apply_async(self, func, args=(), kwds={}, callback=None, error_callback=None):
- imap()函数:
- 对应executor(线程池)里面的map()方法,输出结果与参数列表的顺序一致.
- imap_unordered()函数:
- 不按照加载列表的顺序输出结果,按照执行完毕并成功的先后顺序输出结果.
- Pool(self, processes=None, initializer=None, initargs=(), maxtasksperchild=None, context=None):
通过一个小案例引出多进程编程
1 import os 2 import time 3 4 # fork()函数可以新建一个子进程,fork()只能用于linux/unix下,在windows下是使用不了的 5 # 创建的子进程行为和多线程的行为是不一样的 6 # fork()函数实际上会返回两次.如果在主进程中,pid就会是子进程的一个id,如果pid等于0那么pid就是子进程. 7 # 因为在fork()之后,实际上有两个进程存在,主进程和子进程,通对pid的判断来区分主进程和子进程. 8 pid = os.fork() 9 print("jayden") 10 11 if pid == 0: 12 print("子进程: {}, 父进程: {}".format(os.getpid(), os.getppid())) 13 else: 14 print("我是父进程: {}".format(pid)) 15 16 # sleep的作用??? 17 time.sleep(2) 18 19 """ 20 通过上面的代码,预想一下输出结果: 21 首先会print jayden,第二就是他会在主进程中运行,会打印我是父进程,这时我们预想的结果. 22 但他实际上会不会与我们预想的结果是一样的呢??? 23 24 在linux下运行代码,输出结果: 25 jayden 26 我是父进程: 24474 27 jayden 28 子进程: 24474 , 父进程: 24473 29 30 输出的结果很奇怪,jayden运行了两次,将if...else语句中的两段代码都运行了,根据if...else语句的特点,只能执行两段代码中的 31 一段代码.为什么两段代码都执行了呢???这就涉及到进程和线程不一样的地方,一但运行了fork(),就会立马创建一个进程, 32 这个进程就是windows管理器中的进程. 33 1.fork一个子进程,但是他的父进程依然要向下进行,就会打印出jayden,然后判断条件只能存在一个,打印出我是父进程: 24474. 34 2.子进程会将父进程中的所有的数据原样拷贝到子进程中,包括我们的代码运行,所以说进程的数据和线程之间的数据是完全隔离的. 35 之前介绍,线程可以通过全局变量是可以通信的,但是进程通过全局变量是不能通信的,因为进程的整个数据完全是隔离的. 36 每个进程都有一套自己完整的数据,现在使用fork()出来的数据,会把父进程的数据全部拷贝一份到子进程.然后父进程和子进程就完全 37 隔离了.同时这里面的运行过程也是一样的,子进程也会运行一遍,子进程会运行fork()函数之后代码,fork之前的代码子进程是不会运行的 38 所以说子线程也打印了一次jayden,在子线程中pid的值是0,所以说这段代码在子进程中运行就是jayden, 子进程: 24474 , 父进程: 24473 39 如果将print("jayden")语句放到fork()函数上面,按照刚才的理解,jayden就不会打印两次.运行代码输出结果也是如此. 40 41 如果把time.sleep(2)语句删除执行结果: 42 jayden 43 我是父进程: 24844 44 [root@izhp36e447... ~] # jayden 45 子进程: 24844 , 父进程: 1. 46 通过结果分析: 47 首先父进程打印完成,子进程打印结果并没有接着父进程的打印结果接着打印.是因为父进程运行完就会退出,但是子进程依然可以 48 运行,而且没有退出.我们说是有两个进程,两个进程都是往终端打数据,父进程运行完成并没有sleep,所以说父进程就会直接运行完 49 退出,但是子进程依然存在,而父进程退出,这时子进程就没法退出. 50 51 使用sleep后,当子进程结束后,父进程还没有结束,这时父进程退出后,就可以将子进程也给kill掉. 52 53 """
multiprocessing进行多进程编程
1 """ 2 multiprocessing进行多进程编程 3 4 multiprocessing.Process 创建一个进程 5 """ 6 import multiprocessing 7 import time 8 9 10 def get_html(n): 11 time.sleep(n) 12 print("sub progress {} success".format(n)) 13 return n 14 15 16 if __name__ == '__main__': 17 progress = multiprocessing.Process(target=get_html, args=(2,)) 18 progress1 = multiprocessing.Process(target=get_html, args=(3,)) 19 20 # 获取进程的pid(progress id),没有start之前pid是None 21 print(progress.pid) 22 print(progress1.pid) 23 24 # 开启进程 25 progress.start() 26 progress1.start() 27 28 # 获取进程的pid 29 print(progress.pid) 30 print(progress1.pid) 31 32 # 等待所有进程执行完毕再执行主进程 33 progress.join() 34 progress1.join() 35 print("main progress end") 36 37 """ 38 输出结果: 39 None 40 None 41 3356 42 4908 43 sub progress 2 success 44 sub progress 3 success 45 main progress end 46 """
1 """ 2 自定义类继承multiprocessing.Process类进行多进程编程 3 """ 4 import time 5 import multiprocessing 6 7 8 class GetHtmlProgress(multiprocessing.Process): 9 def __init__(self, n): 10 super().__init__() 11 self.n = n 12 13 def run(self): 14 time.sleep(self.n) 15 print("sub progress {} success".format(self.n)) 16 17 18 if __name__ == '__main__': 19 progress1 = GetHtmlProgress(2) 20 progress2 = GetHtmlProgress(3) 21 22 progress1.start() 23 progress2.start() 24 25 progress1.join() 26 progress2.join() 27 print("main progress end") 28 29 """ 30 输出结果: 31 sub progress 2 success 32 sub progress 3 success 33 main progress end 34 """
使用multiprocessing中的进程池
1 import time 2 import multiprocessing 3 4 5 def get_html(n): 6 time.sleep(n) 7 print("sub progress {} success".format(n)) 8 return n 9 10 11 if __name__ == '__main__': 12 # multiprocessing.Pool(processes=3) 13 # 获取cpu的数量,将cpu的数量作为线程池的数量 14 pool = multiprocessing.Pool(multiprocessing.cpu_count()) 15 # 异步提交任务 16 result = pool.apply_async(get_html, args=(3,)) 17 18 # 单独写一行pool.join()会报错,AssertionError:assert self._state in (CLOSE, TERMINATE) 19 # 必须将进程池关闭,不允许进程池再添加新的任务. 20 pool.close() 21 22 # 将进程池里面所有thread都执行join()方法 23 # 实际上就是等待进程池中的所有任务完成. 24 pool.join() 25 26 # 返回结果的值 27 print(result.get()) 28 29 """ 30 输出结果: 31 sub progress 3 success 32 3 33 """
1 """ 2 imap()函数: 3 对应executor(线程池)里面的map()方法 4 5 """ 6 import time 7 import multiprocessing 8 9 10 def get_html(n): 11 time.sleep(n) 12 print("sub progress {} success".format(n)) 13 return n 14 15 16 if __name__ == '__main__': 17 # multiprocessing.Pool(processes=3) 18 # 获取cpu的数量,将cpu的数量作为线程池的数量 19 pool = multiprocessing.Pool(multiprocessing.cpu_count()) 20 21 # [1,5,3]秒数列表 22 for result in pool.imap(get_html, [1, 5, 3]): 23 print("{} sleep success".format(result)) 24 25 """ 26 输出结果: 27 sub progress 1 success 28 1 sleep success 29 sub progress 3 success 30 sub progress 5 success 31 5 sleep success 32 3 sleep success 33 34 分析: 35 输出的结果的顺序,与[1,5,3]秒数列表的顺序一致.与线程池中的map()方法是一样的 36 """
1 """ 2 imap_unordered()函数: 3 不按照加载列表的顺序输出结果,按照执行完毕并成功的先后顺序输出结果. 4 5 """ 6 import time 7 import multiprocessing 8 9 10 def get_html(n): 11 time.sleep(n) 12 print("sub progress {} success".format(n)) 13 return n 14 15 16 if __name__ == '__main__': 17 # multiprocessing.Pool(processes=3) 18 # 获取cpu的数量,将cpu的数量作为线程池的数量 19 pool = multiprocessing.Pool(multiprocessing.cpu_count()) 20 21 # [1,5,3]秒数列表 22 for result in pool.imap_unordered(get_html, [1, 5, 3]): 23 print("{} sleep success".format(result)) 24 25 """ 26 输出结果: 27 sub progress 1 success 28 1 sleep success 29 sub progress 3 success 30 3 sleep success 31 sub progress 5 success 32 5 sleep success 33 34 分析: 35 输出的结果的顺序,不按照加载列表的顺序输出结果,按照执行完毕并成功的先后顺序输出结果. 36 """
********
posted on 2019-05-03 08:59 jaydenjune 阅读(51) 评论(0) 收藏 举报
浙公网安备 33010602011771号