什么是进程
参考任务管理器,所有任务都是进程
线程包含在进程之内。
一个程序运行起来后,代码 + 用到的资源称之为进程
它是操作系统分配资源的基本单元。
不仅可以通过线程完成多任务,进程同样也可以做到。
进程的状态
工作中,任务数往往大于cpu的核心数。即,一定会有一些任务在执行,而另一些在等待cpu进行执行,因此产生了不同的状态。
就绪状态
执行状态
等待状态
等待满足某些条件,例如一个程序sleep了,此时就处于等待状态
多进程
multiprocessing模块
使用多进程要用到该模块。
Process 创建参数设置
target 如果传递了函数的引用,可以创建进程任务
args 给target指定的函数传递的参数,元祖的方式传参数
kwargs 给target指定的函数命名传参
name 给进程设定一个名字,可以不设置
group 指定进程组,到时候用不到
process 创建实例对象的常用方法
start() 启动,创建子进程
is_alive() 判断进程是否存活
join(timeout) 是否等待子进程执行结束,或者等待多少秒
terminate() 不管任务是否完成逻辑终止子进程
代码实例
from multiprocessing import Process
import time
num =100
def work1():
for i in range(10):
global num
print(F"这个是任务1------{num}")
num += 1
time.sleep(0.5)
def work2():
for i in range(10):
global num
print(F"这个是任务2------{num}")
num += 1
time.sleep(0.5)
# 创建两个进程
if __name__ == '__main__':
# 进程执行的时候不加 __name__ == main 会报错
# 原因是什么呢?
# 如果没有main ,代码会相当于,从模块导入,会陷入无限递归的状态
# 进程之间的资源是独立的, windows下面会报错, linux mac 不会
# 全局变量不进行共享,不会造成数据不安全之类的问题
p1 = Process(target=work1)
p2 = Process(target=work2)
p1.start()
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的方法
apply_async() 使用非租塞方式调用func
close() 关闭pool
terminate() 不管任务是否完成立即终止
join() 主进程阻塞,等待子进程的退出,必须在close或terminate之后使用
import os
import time
from multiprocessing import Process,Queue,Manager,Pool
def work1():
print("进程池---{}".format(os.getpid()))
time.sleep(1)
if __name__ == '__main__':
p = Pool(3)
for i in range(10):
p.apply_async(work1)
p.close()
p.join()
pool中的queue
如果使用pool创建进程,就需要用multiprocessing,manager()中的queue()
例子:
import os
import time
from multiprocessing import Pool,Manager
def work1(q):
print("进程池---{}".format(os.getpid()))
print(q.get())
time.sleep(1)
if __name__ == '__main__':
Manager()
q = Manager().Queue()
for i in range(10):
q.put("你好啊")
p = Pool(3)
for i in range(10):
p.apply_async(work1)
p.close()
p.join()