Python(三十)多进程多线程
之前的文章中有提到单进程和多进程、单线程和多线程之间的关系,想必大家对此应该也有了一定的了解。那么,这篇文章我将带大家深入了解多进程多线程的运行,以及运行后会发生什么情况,出现了问题如何解决更为妥当?
1. 多任务运行控制
1.1. 等待子任务结束
进程或者线程添加join方法之后,会等待子任务结束,如果没有结束,则会阻塞,直到子任务结束,因此join一般都是放在程序的最后。
p1.join()
:主进程等待子任务运行完毕
# 加p1.join(),子进程结束了,主进程才结束
# outputs:
# outer-start: Wed Dec 1 20:05:48 2021
# inner-start: Wed Dec 1 20:05:48 2021
# inner-end: Wed Dec 1 20:05:58 2021
# outer-end: Wed Dec 1 20:05:58 2021
# 未加p1.join(),什么都没加的话,主进程先结束,子进程后结束
# outputs:
# outer-start: Wed Dec 1 20:05:08 2021
# inner-start: Wed Dec 1 20:05:08 2021
# outer-end: Wed Dec 1 20:05:13 2021
# inner-end: Wed Dec 1 20:05:18 2021
1.2. 获取当前进程
在进程内容处获取当前进程,方便查找问题。
print(multiprocessing.current_process())
:获取当前进程对象,与下方的name对应
1.3. 任务名字
修改与添加用户的名字,起到表示作用。
p1.name = '进程1号'
:子进程名为进程1号
1.4. 终止任务
在正常情况下,主进程的结束,并不会影响子进程,但是也可以在主进程结束之后,强制终止子进程。
p1 = multiprocessing.Process(target=func)
:实例化进程对象传给变量p1
p1.terminate()
:主进程结束时,强制关闭子进程
注意线程不能终止,只能等待结束。
import time
import multiprocessing
def new_time():
"""格式化时间"""
return time.asctime(time.localtime(time.time()))
def func():
print('inner-start:',new_time())
time.sleep(10) # 休眠,模拟io耗时操作
print('inner-end:',new_time())
print('outer-start:',new_time())
p1 = multiprocessing.Process(target=func)
p1.start()
time.sleep(5)
# p1.terminate() # 主进程结束时,强制关闭子进程
# p1.join() # 主进程等待子任务运行完毕
# 加p1.join(),子进程结束了,主进程才结束
# outputs:
# outer-start: Wed Dec 1 20:05:48 2021
# inner-start: Wed Dec 1 20:05:48 2021
# inner-end: Wed Dec 1 20:05:58 2021
# outer-end: Wed Dec 1 20:05:58 2021
# 未加p1.join(),也什么处理方式都没加,则主进程先结束,子进程后结束
# outputs:
# outer-start: Wed Dec 1 20:05:08 2021
# inner-start: Wed Dec 1 20:05:08 2021
# outer-end: Wed Dec 1 20:05:13 2021
# inner-end: Wed Dec 1 20:05:18 2021
res = input("是否需要继续等待子进程执行y/n:")
if res == 'y':
p1.join() # 主进程等待子任务运行完毕
elif res == 'n':
p1.terminate() # 主进程结束时,强制关闭子进程
else:
print('请选择正确选项')
print('outer-end:',new_time())
2. 多任务标识
2.1. 进程的pid
在Linux中,只要进程一创建,系统就会分配一个pid,在程序运行过程中,pid都不会改变。
可以通过pid查看进程对资源的使用情况,也可以通过pid来控制进程的运行。
import time
import multiprocessing
def new_time():
"""格式化时间"""
return time.asctime(time.localtime(time.time()))
def func():
print('inner-start:',new_time())
# print(multiprocessing.current_process()) # 获取当前进程对象
# outputs:<Process(进程1号, started daemon)>
time.sleep(10) # 休眠,模拟io耗时操作
print('inner-end:',new_time())
print('outer-start:',new_time())
# print(multiprocessing.current_process()) # 获取当前进程对象
# outputs:<_MainProcess(MainProcess, started)>
p1 = multiprocessing.Process(target=func,daemon=True) # 守护模式daemon,开启守护模式之后,主进程结束,子进程会自动结束,与terminate比起来更加合适
# p1.name = '进程1号' # 改进程名
print('before start:',p1.pid) # 查找进程id
p1.start()
print('after start:',p1.pid)
time.sleep(5)
print('outer-end:',new_time())
2.2. 线程ident
线程是在一个进程当中,所以不会有pid。
线程由python解释器调度,为了调度方便,会有ident类似于操作系统中的pid。
import time
import threading
def new_time():
"""格式化时间"""
return time.asctime(time.localtime(time.time()))
def func():
print('inner-start:',new_time())
time.sleep(10) # 休眠,模拟io耗时操作
print('inner-end:',new_time())
print('outer-start:',new_time())
t1 = threading.Thread(target=func)
print('before start:',t1.ident) # 查找线程id
t1.start()
print('after start:',t1.ident)
time.sleep(5)
print('outer-end:',new_time())
2.3. 生命周期
进程的生命周期开始于start启动,实例化之后,进程并没有启动,只有启动之后才开始有生命周期。
import time
import multiprocessing
def new_time():
"""格式化时间"""
return time.asctime(time.localtime(time.time()))
def func():
print('inner-start:',new_time())
time.sleep(10) # 休眠,模拟io耗时操作
print('inner-end:',new_time())
print('outer-start:',new_time())
p1 = multiprocessing.Process(target=func)
print('before start:',p1.is_alive())
# outputs:
# False
p1.start()
print('after start:',p1.is_alive())
# outputs:
# True
time.sleep(5)
print('outer-end:',new_time())
3. 守护模式
开启守护模式之后,主进程结束,子进程会自动结束。
p1 = multiprocessing.Process(target=func,daemon=True)
:daemon=True开启守护模式
import time
import multiprocessing
def new_time():
"""格式化时间"""
return time.asctime(time.localtime(time.time()))
def func():
print('inner-start:',new_time())
# print(multiprocessing.current_process()) # 获取当前进程对象
# outputs:<Process(进程1号, started daemon)>
time.sleep(10) # 休眠,模拟io耗时操作
print('inner-end:',new_time())
print('outer-start:',new_time())
# print(multiprocessing.current_process()) # 获取当前进程对象
# outputs:<_MainProcess(MainProcess, started)>
p1 = multiprocessing.Process(target=func,daemon=True) # 守护模式daemon,开启守护模式之后,主进程结束,子进程会自动结束,与terminate比起来更加合适
# p1.name = '进程1号' # 改进程名
print('before start:',p1.pid) # 查找进程id
p1.start()
print('after start:',p1.pid)
time.sleep(5)
print('outer-end:',new_time())
4. 面向对象编程
在使用多进程或者多线程时,对应模块可以直接使用,也可以继承之后,自己定制使用。
import redis
import multiprocessing
class RedisProcess(multiprocessing.Process): # 继承进程类
def __init__(self,db,key,value):
super().__init__() # 利用父类的初始化赋值,使我们的实例对象可以成为完整的子进程对象
self.connect = redis.Redis(db=db) # 连接redis非关系型数据库
self.key = key
self.value=value
def set(self):
self.connect.set(self.key,self.value)
def run(self): # 重写了父类multiprocessing.Process里的run方法,如下方start()即可调用
import time
time.sleep(5)
self.set()
myredis1 = RedisProcess(5,'ch','age18')
myredis2 = RedisProcess(6,'bd','age38')
myredis1.start()
myredis2.start()
myredis1.join()
myredis2.join()
# flushall 在linux里运行,则所有redis库数据都消失
文章到这里就结束了!希望大家能多多支持Python(系列)!六个月带大家学会Python,私聊我,可以问关于本文章的问题!以后每天都会发布新的文章,喜欢的点点关注!一个陪伴你学习Python的新青年!不管多忙都会更新下去,一起加油!
Editor:Lonelyroots