进程的概念
进程可以通俗的理解为一个运行的程序或者软件,进程是操作系统资源分配的基本单位。
多进程完成多任务
# 导入线程模块
import multiprocessing
import time
# 多进程完成多任务
def run():
'''子进程需要执行的代码'''
while True:
print('-----2-----')
time.sleep(1)
if __name__ == '__main__':
# 创建子进程
sub_process = multiprocessing.Process(target=run)
# 启动子进程
sub_process.start()
while True:
print('-----1-----')
time.sleep(1)
说明:
Process进程类的参数
给进程传参的方式同线程一样,有两种方式,args用元组的方式,kwargs用字典的方式,name可以指定进程名,target指定任务名,group指定进程组,目前只能用None。
获取当前的进程:multiprocess.current_process()
获取当前进程的编号:current_process.pid os.getpid()
获取父进程的编号:os.getppid()
根据进程的编号杀死进程:os.kill(os.getpid(),9)
进程名.join():主进程等待子进程执行完成代码才继续执行
进程名.termiante():销毁子进程
守护主进程:进程名.daemon = True
注意:
1.进程之间是不共享全局变量的。创建子进程其实就是对主进程的拷贝,进程之间相互独立,访问的全局变量不是同一个。
2.主进程会等待所有的子进程执行结束后才退出。
进程之间的通信 Queue
进程之间的通信可以通过multiprocessing的Queue模块来完成数据传递,Queue本身就是一个消息队列。
import multiprocessing
import time
# 写入数据
def write_data(queue):
for i in range(10):
if queue.full():
print("队列满了")
break
queue.put(i)
time.sleep(0.2)
print(i)
# 读取数据
def read_data(queue):
while True:
# 加入数据从队列取完了,那么跳出循环
if queue.qsize() == 0:
print("队列空了")
break
value = queue.get()
print(value)
if __name__ == '__main__':
# 创建消息队列
queue = multiprocessing.Queue(5)
# 创建写入数据的进程
write_process = multiprocessing.Process(target=write_data, args=(queue,))
# 创建读取数据的进程
read_process = multiprocessing.Process(target=read_data, args=(queue,))
# 启动进程
write_process.start()
# 主进程等待写入进程执行完成以后代码再继续往下执行
write_process.join()
read_process.start()
运行结果:
0
1
2
3
4
队列满了
0
1
2
3
4
队列空了
解释:
在初始化Queue对象的时候,我们可以指定可接收的最大可接收的消息数量,若没有指定或数量为负,那么就代表可接受的消息数量没有上限。
Queue.qsize():返回当前队列包含的消息数量;
Queue.empty():如果队列为空,返回True,反之False , 注意这个操作是不可靠的。
Queue.full():如果队列满了,返回True,反之False;
Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常;
2)如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常;
Queue.get_nowait():相当Queue.get(False);
Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常;
2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常;
Queue.put_nowait(item):相当Queue.put(item, False);
进程池Pool
进程池会根据用户的任务执行情况自动创建进程,而且尽量少创建进程,合理利用进程池中的进程完成多任务。
进程池同步执行多任务
同步执行任务表示池中的任务在执行任务的时候一个任务执行完成才会执行下一个任务,如果没有执行完会等待。
import multiprocessing
import time
# 拷贝任务
def work():
print("复制中...", multiprocessing.current_process().pid)
time.sleep(0.5)
if __name__ == '__main__':
# 创建进程池
# 3:进程池中进程的最大个数,如果不执行最大进程池的可创建进程的个数,默认是创建自己电脑cpu的核数。
pool = multiprocessing.Pool(3)
# 模拟大批量的任务,让进程池去执行
for i in range(5):
# 循环让进程池执行对应的work任务
# 同步执行任务,一个任务执行完成以后另外一个任务才能执行
pool.apply(work)
运行结果:
复制中... 100512
复制中... 68128
复制中... 98924
复制中... 100512
复制中... 68128
进程池异步执行多任务
异步执行多任务表示进程池中的进程同时执行任务,进程之间不会相互等待。
import multiprocessing
import time
# 拷贝任务
def work():
print("复制中...", multiprocessing.current_process().pid)
# 获取当前进程的守护状态
# 提示:使用进程池创建的进程是守护主进程的状态,默认自己通过Process创建的进程是不是守住主进程的状态
# print(multiprocessing.current_process().daemon)
time.sleep(0.5)
if __name__ == '__main__':
# 创建进程池
# 3:进程池中进程的最大个数
pool = multiprocessing.Pool(3)
# 模拟大批量的任务,让进程池去执行
for i in range(5):
# 循环让进程池执行对应的work任务
# 同步执行任务,一个任务执行完成以后另外一个任务才能执行
# pool.apply(work)
# 异步执行,任务执行不会等待,多个任务一起执行
pool.apply_async(work)
# 关闭进程池,意思告诉主进程以后不会有新的任务添加进来
pool.close()
# 主进程等待进程池执行完成以后程序再退出
pool.join()
执行结果:
复制中... 122872
复制中... 61772
复制中... 114636
复制中... 122872
复制中... 114636
注意:
同步执行任务的时候主进程会等待子进程结束之后再结束进程,异步执行的时候不是,异步执行是守护主进程的,即Process类中的daemon设置默认为True。在设置守护主进程的时候,一定的要有关闭进程池的过程,表名不会在添加别的进程任务 。