一、进程
1.多任务的执行方式:并发、并行;
并发:在一段时间内交替去执行任务。单核cpu处理多任务,操作系统轮流让各个软件交替执行。
并行:对于多核cpu处理多任务,操作系统会给cpu的每个内核安排一个执行的软件,多个内核是真正的一起运行软件。多核cpu是并行的执行软件,即:始终是多个软件同时运行。
2.进程的介绍
一个正在运行的程序或者软件就是一个进程。,它是操作系统进行资源分配的基本单位。
进程里面可以创建多个线程,线程是依附在进程里面的,没有进程就没有线程。
3.进程的使用
#导入进程包
import multiprocessing
4.Process进程类的说明
multiprocessing.Process()是继承process.BaseProcess类的,BaseProcess来的初始化参数包括:
group、target、name、args、kwargs;其中target最为重要,表示执行的函数或者方法名;
5.Process创建的实例对象的常用方法:
start():启动子进程实例(创建子进程)
join():等待子进程执行结束
terminate():不管任务是否执行完毕,立即终止进程。
6.进程-》实例:实现多任务同时执行
主进程+子进程:
3个进程(主进程+2个子进程)的方式:
7.获取进程编号
获取进程编号的目的是验证主进程和子进程的关系,可以得知子进程是由那个主进程创建出来的。获取进程编号的两种操作:
1.获取当前进程编号;2.获取当前父进程编号
os.getpid():获取当前进程编号
os.getppid():获取当前父进程编号
#下面的代码,包括了getpid、getppid、multiprocessing.current_process()、start、kill
# -*-coding:utf-8-*-
#进程--实例
'''需求:实现同时执行两个target
'''
import multiprocessing,time,os
#target1:
def pro001():
# 获取当前进程id
pro001_process_id=os.getpid()
# 查看当前代码是由哪个进程执行的multiprocessing.current_process()
ppro001_process_id=os.getppid()#父进程id
print("pro001_process_id:", pro001_process_id,ppro001_process_id, multiprocessing.current_process())
for i in range(3):
print('执行中……pro001')
time.sleep(0.3)
#kill杀死进程,数字9:强制
os.kill(pro001_process_id,9)
def pro002():
# 获取当前进程id
pro002_process_id = os.getpid()
#查看当前代码是由哪个进程执行的multiprocessing.current_process()
print("pro002_process_id:", pro002_process_id, multiprocessing.current_process())
for i in range(3):
print("pro002在主进程中执行……")
time.sleep(0.3)
if __name__ == '__main__':
# 创建子进程(自己手动创建的进程成为子进程)
process_1 = multiprocessing.Process(target=pro001,name='pro001') # group:进程组,目前必须为None,否则报错;
# 创建子进程(自己手动创建的进程成为子进程)
process_2 = multiprocessing.Process(target=pro002)
process_1.start()
process_2.start()
#获取当前进程id
main_process_id = os.getpid()#因为这里执行没有指派子进程,所以获取的是主进程id
print("main_process_id:",main_process_id)#main_process_id: 16412
#但是,上面你只知其进程id,但不知是不是主进程,
# 所以,需要获取当前进程对象,查看当前代码是由哪个进程执行的
print("main_process_id:", main_process_id,multiprocessing.current_process())
#结果:main_process_id: 1428 <_MainProcess name='MainProcess' parent=None started>
8、进程执行带参数的函数
# -*-coding:utf-8-*-
#进程带参数的函数执行
import multiprocessing
def show_info(name,age,msg):
'''
显示name,age,进程信息
:param name:
:param age:
:return:
'''
print(name,":",age,msg,multiprocessing.current_process())
if __name__ == '__main__':
#以元组方式传参,注意:元组中元素顺序与函数的参数一一对应
sub_precess = multiprocessing.Process(target=show_info,args=("ithing",20,"进程args"))
sub_precess.start()
#以字典方式参数,注意:字典中的key与函数中的参数名要一致,没有顺序要求
sub_precess2 = multiprocessing.Process(target=show_info,kwargs={"name":"李四","age":18,"msg":"进程kwargs"})
sub_precess2.start()
#元组、字典混合传参,注意每种方式传参给函数中的哪个参数,args要传入函数参数中的前面的
sub_precess3 = multiprocessing.Process(target=show_info,args=("zhangsan",28,),kwargs={"msg":"进程kwargs、args"})
sub_precess3.start()
9、进程之间不共享全局变量
创建一个子进程,其实是对主进程资源进行拷贝,子进程其实就是主进程的一个副本;子进程改变的数据,都是该进程内部的,对主进程、其他子进程无影响;下面的例子的结果:读取数据的进程打印的内容是不变的,不论改变数据的进程如何执行。
# -*-coding:utf-8-*-
#进程带参数的函数执行
import multiprocessing,time
#定义全局变量
data=list()
#改变全局变量
def add_data():
for i in range(3):
print(i)
data.append(i)
time.sleep(0.3)
#读取全局变量
def read_data():
print(data)
time.sleep(0.2)
if __name__ == '__main__':
#创建子进程,改变全局变量
add_process = multiprocessing.Process(target=add_data,name="add_data")
add_process.start()
#创建子进程,读取全局变量
read_process = multiprocessing.Process(target=read_data,name="read_data")
read_process.start()
10、主进程会等待所有的子进程执行结束再结束
解决方式:
1.子进程设置为守护主进程,这样主进程退出,子进程就销毁。
2.让主进程退出之前先让子进程销毁
子进程守护主进程:sub_process.daemon = True
#-*-coding:utf-8-*-
#主进程要等待子进程执行结束后再结束
#为了让子进程随着主进程的销毁而结束,有两种方式:
#1.让子进程设置为守护主进程,主进程退出子进程销毁,子进程会依赖主进程
import multiprocessing,time
def proce_func():
while True:
print("我是子进程……")
time.sleep(0.2)
if __name__ == '__main__':
#创建子进程
sub_process = multiprocessing.Process(target=proce_func)
#把子进程设置为守护主进程,以后主进程退出,子进程就销毁
sub_process.daemon = True
sub_process.start()
time.sleep(0.5)
print("over")
#最终的结果:子进程运行3次,主进程执行到最后一句代码,就完毕。
主进程退出之前先让子进程销毁:sub_process.terminate()
#-*-coding:utf-8-*-
#主进程要等待子进程执行结束后再结束
#为了让子进程随着主进程的销毁而结束,有两种方式:
#1.让子进程设置为守护主进程,主进程退出子进程销毁,子进程会依赖主进程
import multiprocessing,time
def proce_func():
while True:
print("我是子进程……")
time.sleep(0.2)
if __name__ == '__main__':
#创建子进程
sub_process = multiprocessing.Process(target=proce_func)
sub_process.start()
time.sleep(0.5)
# 把主进程退出之前,终止子进程
sub_process.terminate()
print("over")
#最终的结果:子进程运行3次,主进程执行到最后一句代码,就完毕。
二、线程
在python中,进程可以实现多任务的执行,同样线程也可以。
1.线程的概念
线程是进程中执行代码的一个分支,每个执行分支(线程)要想工作执行代码需要cpu进行调度,也就是说线程是cpu调度的基本单位。每个进程至少有一个线程,而这个线程就是我们通常说的主线程。
线程的作用:多线程可以完成多任务。
说明:程序启动默认会有一个主线程,程序员自己创建的线程可以称为子线程。
2.使用多线程执行多任务
导入线程模块:import threading
线程类参数说明:Thread([group[,target[,name[,args[,kwargs]]]]])
group:线程组,目前只能使用None
target:执行的目标任务名
args:以元组的方式给执行任务传参
kwargs:以字典方式给执行任务传参
name:线程名,一般不作设置,默认Thread-N,N为1递增的整数;
启动线程:start
示例:
# -*-coding:utf-8-*-
#多线程运行多任务
#导入线程模块
import threading,time
def thread001():
#获取当前线程对象
current_thread=threading.current_thread()
for i in range(3):
print("子线程1",current_thread)
time.sleep(0.2)
def thread002():
#获取当前线程对象
current_thread=threading.current_thread()
for i in range(3):
print("子线程2",current_thread)
time.sleep(0.2)
if __name__ == '__main__':
print(threading.current_thread())
#创建子线程1
thread_001=threading.Thread(target=thread001)
#启动子线程执行对应的线程
thread_001.start()
# 创建子线程2
thread_002 = threading.Thread(target=thread002)
# 启动子线程执行对应的线程
thread_002.start()
3.线程执行带有参数的函数
# -*-coding:utf-8-*-
#线程执行待参数的函数
import threading,time
def show_info(name,age):
print(name,age)
if __name__ == '__main__':
#创建子线程,元组形式入参,注意:顺序一致
sub_thread = threading.Thread(target=show_info,args=("ithing",20))
sub_thread.start()
# 创建子线程,字典形式入参,注意名称与函数的参数名称一致
sub_thread1 =threading.Thread(target=show_info,kwargs={"name":"ithing1","age":18})
sub_thread1.start()
# 创建子线程,以元组、字典混合入参
sub_thread2 = threading.Thread(target=show_info,args=("ithing",), kwargs={"age": 18})
sub_thread2.start()
4.线程的注意点
1.线程之间执行是无序的
2.主线程会等待所有的子线程执行结束再结束
为了克服这点,需要将子线程设置为守护主线程,设置主线程有两种方式:
3.线程之间共享全局变量
4.4.线程之间共享全局变量数据出现错误问题
举例描述:
解决方式1:线程等待(join)子线程一个运行完毕再运行另一个子线程,避免同时对全局变量进行获取。
解决方式2:互斥锁
互斥锁:对共享数据进行锁定,保证同一时刻只能有一个线程去操作。上锁lock.acquire()与释放锁lock.release()需要一起出现,否则会出现死锁的情况,死锁那么程序就一直停留,不会结束。