什么是进程?
当你想在电脑上听歌的时候,应该是先找到网易云音乐的应用程序,打开才能播放音乐。当我们双击打开的时候,操作系统骄傲那个程序装载到内存中,cpu为它分配资源,然后才能运行,运行起来的程序就被称为进程。注意:程序只有一个,但是进程可以有多个
进程的状态
在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行
和阻塞。
(1)就绪(Ready)状态
当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程
状态称为就绪状态。
(2)执行/运行(Running)状态
当进程已获得处理机,其程序正在处理机上执行,此时的
进程状态称为执行状态。
(3)阻塞(Blocked)状态
正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处
理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不
能满足、等待信件(信号)等。
实现进程
实现进程有两种方式,创建 multiprocessing的实例化对象和继承process类
- 继承process类
import os
from multiprocessing import Process
from urllib import request
# 1.继承process类
class Process_class(Process):
# 2.使用父类的初始化方法
# 因为Process类本身也有__init__方法,定义这个类相当于 重写这个方法
def __init__(self,url):
super().__init__()
self.url = url
# 3. 重写Process类的run方法
def run(self):
print("当前进程:",os.getpid())
# 1.文件名
file_name = self.url.split("/")[-1]
# 2.网络请求
response = request.urlopen(self.url)
# 3. 获取响应内容
content = response.read()
# 4.保存图片
with open(file_name, "wb") as f:
f.write(content)
if __name__ == '__main__':
url_list = [
"http://www.langlang2017.com/img/banner1.png",
"http://www.langlang2017.com/img/banner4.png"
]
for url in url_list:
p = Process_class(url)
p.start()
print("主进程",os.getppid())
- 创建 multiprocessing的实例化对象
import os
from urllib import request
from multiprocessing import Process
def downloder(url,**kwargs):
"""
下载器
:param url: 图片网址
:param kwargs: 字典参数
:return: none
"""
print("当前进程id",os.getpid())
print("获取其父程序的id",os.getppid())
print("关键参数",kwargs["pro"])
# 1.文件名
file_name = url.split("/")[-1]
# 2.网络请求
response = request.urlopen(url)
# 3. 获取响应内容
content = response.read()
# 4.保存图片
with open(file_name,"wb") as f:
f.write(content)
if __name__ == '__main__':
# for i in range(1,5):
# url = "http://www.langlang2017.com/img/banner%d.png"%i
# p = Process(target=downloder,args=(url,))
# p.start()
# 姓名列表
name_list = ["进程1--张铁蛋","进程2--张翠花"]
# 进程列表
p_list = []
# 图片链接列表
url_list = [
"http://www.langlang2017.com/img/banner1.png",
"http://www.langlang2017.com/img/banner4.png"
]
i = 0
for url in url_list:
n = name_list[i]
i+=1
p = Process(target=downloder,name=n,args=(url,),kwargs={"pro":"最高级"})
print("子进程(%s)将要执行。。。"%p.name)
p.start()
p_list.append(p)
# 为了确保所有子进程结束
for p in p_list:
p.join()
print("主进程id:",os.getpid())
进程之间的通讯
队列:
刚才我们说了进程可以理解为复制了一份程序有加载到了内存了,进程之间是独立的,如果
我想两个进程之间进行通讯怎么办呢?我们可以使用Queue 队列,队列是一种先进先出的存
储数据结构,就比如排队上厕所一个道理。
两个进程通讯,就是一个子进程往queue中写内容,另一个进程从queue中取出数据。就实现
了进程间的通讯了
1. 创建 queue队列对象 q = multiprocessing.Queue(3) # 3表示只能存放3个数据
参数 :maxsize是队列中允许的大项数。如果省略此参数,则无大小限制。
返回值q 是队列对象
2. put()方法 ,向队列中存放数据。如果队列已满,此方法将阻塞至有空间可用为止。
3. 3. get()返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。
4. 4. get_nowait(): 不等待,直接抛出异常
5. 5. full()如果q已满,返回为True
6. 6. q.empty() 如果调用此方法时 q为空,返回True
进程池
当需要创建的子进程数量不多时,我们可以直接利用multiporcessing中的Process动态生成
多个进程,创建进程池对象的时候可以指定一个大进程数,当有新的请求提交到进程池中,如果池中的进程数还没有满,那么就会创建一个新的进程用来执行该请求,但是如果池中的进程数满了,该请求就会等待,知道进程池中的进程有结束的了,才会使用这个结束的进程来执行新的任务。
join 主进程等待所有子进程执行完毕,必须在close之后。
close 等待所有进程结束才关闭线程池
from multiprocessing import Pool
import time
def down_load(movie_name):
for i in range(5):
print('电影:{},下载进度{}%'.format(movie_name,(i/4* 100)))
time.sleep(1)
def alert(movie_name):
print('恭喜{}下载完成了...'.format(movie_name))
if __name__ == '__main__':
movie_lst =['西红柿首富','功夫小子','功夫熊猫','叶问','功夫','战 狼','红海行动']
pool = Pool(3)
for movie_name in movie_lst:
pool.apply_async(down_load, (movie_name,), callback=alert)
pool.close()
pool.join()