python 多进程
什么是进程
参考任务管理器,所有任务都是进程
线程包含在进程之内。
一个程序运行起来后,代码 + 用到的资源称之为进程
它是操作系统分配资源的基本单元。
不仅可以通过线程完成多任务,进程同样也可以做到。
进程的状态
工作中,任务数往往大于cpu的核心数。即,一定会有一些任务在执行,而另一些在等待cpu进行执行,因此产生了不同的状态。
就绪状态
运行条件都已满足,在等待cpu执行
执行状态
cpu正在执行其功能
等待状态
等待满足某些条件,例如一个程序sleep了,此时就处于等待状态
多进程
多进程可以做到并行,而多线程不行
multiprocessing模块
使用多进程要用到该模块。
Process 创建参数设置
target 如果传递了函数的引用,可以创建进程任务
args 给target指定的函数传递的参数,元祖的方式传参数
kwargs 给target指定的函数命名传参
name 给进程设定一个名字,可以不设置
group 指定进程组,到时候用不到
process 创建实例对象的常用方法
start() 启动,创建子进程
is_alive() 判断进程是否存活
join(timeout) 是否等待子进程执行结束,或者等待多少秒
terminate() 不管任务是否完成逻辑终止子进程
代码实例
1 from multiprocessing import Process 2 import time 3 num =100 4 5 def work1(): 6 for i in range(10): 7 global num 8 print(F"这个是任务1------{num}") 9 num += 1 10 time.sleep(0.5) 11 def work2(): 12 for i in range(10): 13 global num 14 print(F"这个是任务2------{num}") 15 num += 1 16 time.sleep(0.5) 17 # 创建两个进程 18 if __name__ == '__main__': 19 # 进程执行的时候不加 __name__ == main 会报错 20 # 原因是什么呢? 21 # 如果没有main ,代码会相当于,从模块导入,会陷入无限递归的状态 22 # 进程之间的资源是独立的, windows下面会报错, linux mac 不会 23 # 全局变量不进行共享,不会造成数据不安全之类的问题 24 p1 = Process(target=work1) 25 p2 = Process(target=work2) 26 p1.start() 27 p2.start()
个人理解
运行一个进程的时候,系统会划分出来一块内存,存储这个进程的相关资源
属于该进程的线程是会使用进程的相关资源的,在进程的内存块中划出小块内存支持线程运行。
进程间全局变量则不共享,原因是因为使用的并非是同一块内存地址。
进程,线程之间的区别联系
线程存在于进程之中
进程间存在于不同的内存地址中,进程之间全局变量不共享。
那么如果想要共享,实现进程间的通讯问题。
则需要使用到多进程模块下的队列。
前面学到的queue模块,虽然是线程安全的,但不适用于多进程
需要使用的事multiprocessing下的Queue模块
量模块在内置方法上没什么区别,但是多进程中的queue更为强大、。
区别为Queue是各子进程私有,multiprocessing.Queue是各子进程共有。
看一下代码实例
def work1(q): while True: if q.qsize() > 0 : url = q.get() requests.get(url) print("work1 正在执行任务----") def work2(q): while True: if q.qsize() > 0: url = q.get() requests.get(url) print("work2 正在执行任务----") if __name__ == '__main__': # 进程执行的时候不加 __name__ == main 会报错 # 原因是什么呢? # 如果没有main ,代码会相当于,从模块导入,会陷入无限递归的状态 # 进程之间的资源是独立的, windows下面会报错, linux mac 不会 # 全局变量不进行共享,不会造成数据不安全之类的问题 # 注意!!! 如果吧队列放到全局变量中,就依然不会行程进程之间资源共享 # 原因跟之前没有加main是一样的, q =Queue() # 通过多进程下面的queue,然后穿参数进去,然后进程之间共同享有queue资源 for i in range(10): q.put("http://www.baidu.com") p1 = Process(target=work1,args=(q,)) p2 = Process(target=work2,args=(q,)) p1.start() p2.start()
进程池子
当需要创新的子进程数量不多时,利用multiprocessing中的process动态生成多个线程。
但是如果上百甚至上千个目标,手动去创建进程的工作量太大。
此时可以使用multiprocessing模块提供的pool方法。
初始化pool时,可以指定一个最大的进程数,当有新的请求提交到pool中时
如果池子还没满,那么就会创建一个新的进程用来执行该请求,
但是如果进程池内数量已达到最大,
那么请求就会等待,等到池中有进程结束,才会用之前的进程来执行新任务。
pool的方法
1 apply_async() 使用非租塞方式调用func 2 close() 关闭pool 3 terminate() 不管任务是否完成立即终止 4 join() 主进程阻塞,等待子进程的退出,必须在close或terminate之后使用 5 import os 6 import time 7 from multiprocessing import Process,Queue,Manager,Pool 8 def work1(): 9 print("进程池---{}".format(os.getpid())) 10 time.sleep(1) 11 if __name__ == '__main__': 12 p = Pool(3) 13 for i in range(10): 14 p.apply_async(work1) 15 16 p.close() 17 p.join()
pool中的queue
如果使用pool创建进程,就需要用multiprocessing,manager()中的queue()
1 例子: 2 import os 3 import time 4 from multiprocessing import Pool,Manager 5 6 def work1(q): 7 print("进程池---{}".format(os.getpid())) 8 print(q.get()) 9 time.sleep(1) 10 if __name__ == '__main__': 11 Manager() 12 q = Manager().Queue() 13 for i in range(10): 14 q.put("你好啊") 15 p = Pool(3) 16 for i in range(10): 17 p.apply_async(work1) 18 p.close() 19 p.join()