什么是进程
狭义定义:进程就是一段程序的执行过程。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
进程和程序的区别
程序只是一组指令的集合,它本身没有任何运行的含义,它是静态的。
进程程序的执行实例,是动态的,有自己的生命周期,有创建,有开始,有运行,有终止。
进程和程序不是一一对应的,一个程序可以对应多个进程,一个进程也可以执行一个或者多个程序。
举例:
我们打开两个爱奇艺一个看电视剧,一个看电影
我们可以这样理解:编写完的代码,没有运行时称为程序,正在运行的代码,会启动一个(或多个)进程。
程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。
如图这写软件都是一个个的程序而任务管理器中的都是进程
python中如何创建一个进程
在python中,进程是通过multiprocessing多进程模块来创建的,multiprocessing模块提供了⼀个Process类来创建进程对象。
Process语法结构:
p1=multiprocessing.Process(target=func)
Process(group, target, name, args, kwargs)主要参数说明:
target:表示调用对象,即子进程要执行的任务
args:给target指定的函数传递的参数,以元组的⽅式传递
kwargs:给target指定的函数传递命名参数
其他参数可以自行查看底层代码(鼠标放到Process上按住ctrl点击查看)
Process常用方法:
p.start() 启动进程,并调用该子进程中的p.run()方法
p.join(timeout):主进程等待⼦进程执⾏结束再结束,timeout是可选的超时时间,默认None
is_alive():判断进程⼦进程是否还存活返回值为bool值即True 或者False
p.terminate() ⽴即终⽌⼦进程
主进程和子进程
通过在一个主进程下创建多个子进程可以帮助我们加速程序的运行,并且提高工作效率
样例1
------------未添加子进程---------------------
import os, multiprocessing, time
def work():
print('--------开始运行函数work----------')
s1 = time.time()
print('进程名称为{},进程号{}'.format(multiprocessing.current_process().name,
multiprocessing.current_process().pid))
time.sleep(2)
s2 = time.time()
print(f'work函数运行时间为{s2 - s1}')
print('--------work函数运行结束----------')
if __name__ == '__main__':
print('--********--开始运行主线程--*****--')
print('主线程名字为{},主线程好为{}'.format(multiprocessing.current_process().name,
multiprocessing.current_process().pid))
start_time = time.time()
# p1 = multiprocessing.Process(target=work)
# p1.start()
work()
time.sleep(1)
end_time = time.time()
print('主线程运行时间为{}'.format(end_time - start_time))
print('--*********--主线程运行结束--*******--')
运行结果输出:
--********--开始运行主线程--*****--
主线程名字为MainProcess,主线程好为10136
--------开始运行函数work----------
进程名称为MainProcess,进程号10136
work函数运行时间为2.013166666030884
--------work函数运行结束----------
主线程运行时间为3.0168092250823975
--*********--主线程运行结束--*******--
样例2
---------------添加子线程--------------------------
import os, multiprocessing, time
def work():
print('--------开始运行子线程----------')
s1 = time.time()
print('子进程名称为{},子进程号{}'.format(multiprocessing.current_process().name,
multiprocessing.current_process().pid))
time.sleep(2)
s2 = time.time()
print(f'子进程运行时间为{s2 - s1}')
print('--------子线程运行结束----------')
if __name__ == '__main__':
print('--********--开始运行主线程--*****--')
print('主线程名字为{},主线程好为{}'.format(multiprocessing.current_process().name,
multiprocessing.current_process().pid))
start_time = time.time()
p1 = multiprocessing.Process(target=work)
p1.start()
time.sleep(1)
end_time = time.time()
print('主线程运行时间为{}'.format(end_time - start_time))
print('--*********--主线程运行结束--*******--')
运行结果:
--********--开始运行主线程--*****--
主线程名字为MainProcess,主线程好为8328
--------开始运行子线程----------
子进程名称为Process-1,子进程号15844
主线程运行时间为1.017944574356079
--*********--主线程运行结束--*******--
子进程运行时间为2.0088047981262207
--------子线程运行结束----------
通过样例1和样例2对比,明显会发现样例2的主进程运行时间明显小于样例1,说明添加子进程会提高效率,但是进程会消耗CPU和内存,所以我们不可能创建无限多的线程。
守护进程
如代码所示,我们这个文件运行是一个主进程,其中我们针对first_work和second_work两个函数给它们分别创建了两个子进程,子进程和主进程是相互独立的,各运行各的,即使主进程死了,子进程依然可以运行,这样看来子进程就是一个孤儿进程,实际业务
中,很多主业务都是要等子业务结束后才能结束,这时候就引入了守护线程即join()方法
##孤儿进程
import os, multiprocessing, time
def work():
print('--------开始运行子线程----------')
s1 = time.time()
print('子进程名称为{},子进程号{}'.format(multiprocessing.current_process().name,
multiprocessing.current_process().pid))
time.sleep(2)
s2 = time.time()
print(f'子进程运行时间为{s2 - s1}')
print('--------子线程运行结束----------')
if __name__ == '__main__':
print('--********--开始运行主线程--*****--')
print('主线程名字为{},主线程好为{}'.format(multiprocessing.current_process().name,
multiprocessing.current_process().pid))
start_time = time.time()
p1 = multiprocessing.Process(target=work)
p1.start()
time.sleep(1)
end_time = time.time()
print('主线程运行时间为{}'.format(end_time - start_time))
print('--*********--主线程运行结束--*******--')
运行结果:
--********--开始运行主线程--*****--
主线程名字为MainProcess,主线程好为8328
--------开始运行子线程----------
子进程名称为Process-1,子进程号15844
主线程运行时间为1.017944574356079
--*********--主线程运行结束--*******--
子进程运行时间为2.0088047981262207
--------子线程运行结束----------
##守护线程
import os,multiprocessing,time
def first_work():
print('-----子进程first_work启动-----')
f1 = time.time()
for i in range(1, 5):
time.sleep(2)
print(f'第{i}次执行进程{multiprocessing.current_process().name},进程号为{os.getpid()}')
f2 = time.time()
print('-----子进程first_work结束-----')
print('first_work子进程号{},运行时间{}'.format(os.getpid(), f2 - f1))
def second_work():
print('-----子进程second_work开始-----')
s1 = time.time()
for i in range(1, 3):
time.sleep(2)
print(f'第{i}次进程{multiprocessing.current_process().name},进程号为{os.getpid()}')
s2 = time.time()
print('-----子进程second_work结束-----')
print('second_work子进程号{},运行时间{}'.format(os.getpid(), s2 - s1))
if __name__ == '__main__':
print('========开始运行主线程==========')
start_time = time.time()
p1 = multiprocessing.Process(target=first_work)
p1.start()
p2 = multiprocessing.Process(target=second_work)
p2.start()
p1.join() # 添加守护进程,p1运行结束,主进程才继续往下运行
time.sleep(2)
end_time = time.time()
print('========主线程运行结束==========')
print(f'主进程进程号{os.getpid()},执行时间{end_time - start_time}') #发现主线程的运行时间大概为p1运行时间+2s
运行结果输出:
========开始运行主线程==========
-----子进程first_work启动-----
-----子进程second_work开始-----
第1次执行进程Process-1,进程号为9440
第1次进程Process-2,进程号为2076
第2次进程Process-2,进程号为2076
-----子进程second_work结束-----
second_work子进程号2076,运行时间4.018338680267334
第2次执行进程Process-1,进程号为9440
第3次执行进程Process-1,进程号为9440
第4次执行进程Process-1,进程号为9440
-----子进程first_work结束-----
first_work子进程号9440,运行时间8.033899545669556
========主线程运行结束==========
主进程进程号9204,执行时间10.122438430786133
通过对比以上两段代码,没有守护线程的情况下,即使主进程死了,子进程依然在运行,添加了守护线程后保证了子进程运行完之前,主进程依然存在。