进程的五状态图:
created:进程已经创建,但未被OS接纳为可执行进程。(还没有申请到相应的资源)。
ready:进程做好了准备,准备执行(只等待处理机)。
running:该进程正在执行(单处理机,某一时刻仅一个进程占用处理机)。
waiting:等待某事件发生才能执行,如等待I/O完成。
终止状态.
1.进程的创建
1.1 fork()函数
linux系统中,用fork()函数
import os
import time
print('当前进程的pid',os.getpid())
print('当前进程的父进程pid',os.getppid())
print('开始创建子进程...')
p = os.fork()
if p==0:
print('这是子进程返回的,子进程的pid,父进程的pid',os.getpid(),os.getppid())
else:
print('这是父进程返回的,返回值是子进程的pid,为',p)
执⾏到os.fork()时,操作系统会创建⼀个新的进程复制⽗进程的所有信息到⼦进程中
普通的函数调⽤,调⽤⼀次,返回⼀次,但是fork()调⽤⼀次,返回两次
⽗进程和⼦进程都会从fork()函数中得到⼀个返回值,⼦进程返回是0,⽽⽗进程中返回⼦进程的 id号
1.2 multiprocessing.Process类
Windows没有fork调⽤,由于Python是跨平台的, multiprocessing模块就是跨平台版本的多进程模块。multiprocessing模块提供了⼀个Process类来代表⼀个进程对象。
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调⽤对象;
args:表示调⽤对象的位置参数元组;
kwargs:表示调⽤对象的关键字参数字典;
name:为当前进程实例的别名;
group:⼤多数情况下⽤不到;
Process类常⽤⽅法:
is_alive(): 判断进程实例是否还在执⾏; join([timeout]): 是否等待进程实例执⾏结束,或等待多少秒;
start(): 启动进程实例(创建⼦进程); run(): 如果没有给定target参数,对这个对象调⽤start()⽅法时,
就将执 ⾏对象中的run()⽅法; terminate(): 不管任务是否完成,⽴即终⽌;
1.2.1 多进程编程方法1: 实例化对象
p = multiprocessing.Process()
from multiprocessing import Process
import time
def task1():
print('听音乐')
time.sleep(1)
def task2():
print('编程')
time.sleep(0.5)
# def no_multi():
# for i in range(2):
# task1()
#
# for i in range(5):
# task2()
def multi():
processes = []
for i in range(2):
p = Process(target=task1,name='音乐任务')
processes.append(p)
print(p.name)
p.start()
for i in range(5):
p = Process(target=task2,name='编程任务')
processes.append(p)
print(p.name)
p.start()
[process.join() for process in processes] #join方法,等待所有的子进程执行结束,再执行主进程
if __name__ == '__main__':
start_time = time.time()
# no_multi()
multi()
end_time = time.time()
print('花费时间:',end_time-start_time)
1.2.2 多进程编程方法2: 创建子类
重写run()方法,函数里面的内容是任务。如果需要传参,在__init__函数中先super继承父类Process,再自定义参数即可。
import time
from multiprocessing import Process
class myProcess(Process):
"""
创建自己的进程类,父类是Process,重写run方法
"""
def __init__(self,name):
"""如果任务需要传参,在构造方法里实现
首先super()继承父类的init,再自定义参数"""
super(myProcess, self).__init__()
self.name=name
def run(self):
"""
开启进程:p.start()---->相当于p.run()
重新run方法,内容是要执行的任务
:return:
"""
print('listen music,歌曲名称:',self.name)
time.sleep(1)
if __name__ == '__main__':
for i in range(10):
p = myProcess('第%s首歌' %(i+1))
# p.start()
1.2.3 多进程编程方法3:进程池
为什么需要进程池:
当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。
from multiprocessing import Process, Pool
import time
def is_prime(num):
if num == 1:
return False
for i in range(2,num):
if num%i == 0:
return False
else:
return True
def task(num):
if is_prime(num):
print('%s是素数'%(num))
def multi(start,end):
processes = []
for num in range(start,end+1):
p = Process(target=task,args=(num,))
p.start()
processes.append(p)
[process.join() for process in processes]
def no_multi(start,end):
for i in range(start,end):
task(i)
def use_pool():
"""使用进程池"""
p = Pool(multiprocessing.cpu_count())
p.map(task,list(range(1,500000)))
p.close() #关闭进程池
p.join() #阻塞,等待所有的子进程执行结束,再执行主进程
if __name__ == '__main__':
start_time = time.time()
# multi(1,4000) #7.436190128326416
# no_multi(1,500000) #1.3182339668273926
use_pool() #0.9440164566040039
end_time = time.time()
print('所用时长',end_time-start_time)
2.进程间通信
2.1 通信目的
2.2 通信方式
2.2.1 消息队列
可以使⽤multiprocessing模块的Queue实现多进程之间的数据传递,Queue 本身是⼀个消息列队程序。
Queue.qsize(): 返回当前队列包含的消息数量;
Queue.empty(): 如果队列为空,返回True,反之False ;
Queue.full(): 如果队列满了,返回True,反之False;
Queue.get([block[, timeout]]):
获取队列中的⼀条消息,然后将其从列队中移除,block默认值为True;
Queue.get_nowait():
相当Queue.get(False);
Queue.put(item,[block[, timeout]]):
将item消息写⼊队列,block默认值 为True;
Queue.put_nowait(item):
相当Queue.put(item, False)
用创建子类的方式 实现消息队列的通信方式
# 生产者消费者模型) 用继承Process类的方式,实现消息队列的通信方式
from multiprocessing import Process,Queue
import time
class Producer(Process):
def __init__(self,queue):
super(Producer, self).__init__()
self.queue = queue
def run(self):
#将需要通信的数据写入队列中
for i in range(10):
self.queue.put(i)
time.sleep(0.5)
print('传递消息,内容为%s' %(i))
class Consumer(Process):
def __init__(self,queue):
super(Consumer, self).__init__()
self.queue = queue
def run(self):
while True:
time.sleep(0.5)
recvData = self.queue.get()
print('接收到另一进程传递的数据:%s' %(recvData))
if __name__ == '__main__':
q = Queue()
p1 = Producer(q)
p2 = Consumer(q)
p1.start()
p2.start()
p1.join()
p2.join()