什么是进程

参考任务管理器,所有任务都是进程
线程包含在进程之内。

一个程序运行起来后,代码 + 用到的资源称之为进程
它是操作系统分配资源的基本单元。
不仅可以通过线程完成多任务,进程同样也可以做到。

进程的状态

工作中,任务数往往大于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. def work1():
  5. for i in range(10):
  6. global num
  7. print(F"这个是任务1------{num}")
  8. num += 1
  9. time.sleep(0.5)
  10. def work2():
  11. for i in range(10):
  12. global num
  13. print(F"这个是任务2------{num}")
  14. num += 1
  15. time.sleep(0.5)
  16. # 创建两个进程
  17. if __name__ == '__main__':
  18. # 进程执行的时候不加 __name__ == main 会报错
  19. # 原因是什么呢?
  20. # 如果没有main ,代码会相当于,从模块导入,会陷入无限递归的状态
  21. # 进程之间的资源是独立的, windows下面会报错, linux mac 不会
  22. # 全局变量不进行共享,不会造成数据不安全之类的问题
  23. p1 = Process(target=work1)
  24. p2 = Process(target=work2)
  25. p1.start()
  26. p2.start()

个人理解

运行一个进程的时候,系统会划分出来一块内存,存储这个进程的相关资源
属于该进程的线程是会使用进程的相关资源的,在进程的内存块中划出小块内存支持线程运行。
进程间全局变量则不共享,原因是因为使用的并非是同一块内存地址。

进程,线程之间的区别联系
线程存在于进程之中
进程间存在于不同的内存地址中,进程之间全局变量不共享。
那么如果想要共享,实现进程间的通讯问题。
则需要使用到多进程模块下的队列。

前面学到的queue模块,虽然是线程安全的,但不适用于多进程
需要使用的事multiprocessing下的Queue模块
量模块在内置方法上没什么区别,但是多进程中的queue更为强大、。

区别为Queue是各子进程私有,multiprocessing.Queue是各子进程共有。
看一下代码实例

  1. def work1(q):
  2. while True:
  3. if q.qsize() > 0 :
  4. url = q.get()
  5. requests.get(url)
  6. print("work1 正在执行任务----")
  7. def work2(q):
  8. while True:
  9. if q.qsize() > 0:
  10. url = q.get()
  11. requests.get(url)
  12. print("work2 正在执行任务----")
  13. if __name__ == '__main__':
  14. # 进程执行的时候不加 __name__ == main 会报错
  15. # 原因是什么呢?
  16. # 如果没有main ,代码会相当于,从模块导入,会陷入无限递归的状态
  17. # 进程之间的资源是独立的, windows下面会报错, linux mac 不会
  18. # 全局变量不进行共享,不会造成数据不安全之类的问题
  19. # 注意!!! 如果吧队列放到全局变量中,就依然不会行程进程之间资源共享
  20. # 原因跟之前没有加main是一样的,
  21. q =Queue()
  22. # 通过多进程下面的queue,然后穿参数进去,然后进程之间共同享有queue资源
  23. for i in range(10):
  24. q.put("http://www.baidu.com")
  25. p1 = Process(target=work1,args=(q,))
  26. p2 = Process(target=work2,args=(q,))
  27. p1.start()
  28. p2.start()

进程池子

当需要创新的子进程数量不多时,利用multiprocessing中的process动态生成多个线程。
但是如果上百甚至上千个目标,手动去创建进程的工作量太大。
此时可以使用multiprocessing模块提供的pool方法。

初始化pool时,可以指定一个最大的进程数,当有新的请求提交到pool中时
如果池子还没满,那么就会创建一个新的进程用来执行该请求,
但是如果进程池内数量已达到最大,
那么请求就会等待,等到池中有进程结束,才会用之前的进程来执行新任务。

pool的方法

  1. apply_async() 使用非租塞方式调用func
  2. close() 关闭pool
  3. terminate() 不管任务是否完成立即终止
  4. join() 主进程阻塞,等待子进程的退出,必须在closeterminate之后使用
  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. p.close()
  16. p.join()

pool中的queue

如果使用pool创建进程,就需要用multiprocessing,manager()中的queue()

  1. 例子:
  2. import os
  3. import time
  4. from multiprocessing import Pool,Manager
  5. def work1(q):
  6.   print("进程池---{}".format(os.getpid()))
  7.   print(q.get())
  8.   time.sleep(1)
  9. if __name__ == '__main__':
  10. Manager()
  11. q = Manager().Queue()
  12. for i in range(10):
  13.   q.put("你好啊")
  14. p = Pool(3)
  15. for i in range(10):
  16.   p.apply_async(work1)
  17. p.close()
  18. p.join()