一:进程
1:概念:
进程:操作系统进行资源分配的基本单位。
进程知识点总结:
1:导入进程模块
import multiprocess
2:创建子进程
p1 = multiprocess.Process(target=sing)
3:启动子进程
p1.start()
4:获取进程对象
multiprocessing.current_process()
5:获取进程ID
os.getpid()
6:获取父进程ID
os.getppid()
7:杀死进程
os.kill(os.getpid(), 9)
8:进程带有参数
元组传参
p1 = multiprocessing.Process(target=sing, args=(6,))
字典传参
注意:kwargs中键必须和参数名相同
p2 = multiprocessing.Process(target=dance, kwargs={"num": 4})
9:设置守护线程
子进程对象名.daemon = True
子进程自杀:
子进程对象名.tarminate()
线程知识点总结:
1:导线程包
import threading
2:创建子线程
t1 = threading.Thread(target=sing)
3:启动子线程
t1.start()
4:获取线程对象
threading.current_thread()
5:线程的传参方式:
t1 = threading.Thread(target=sing, args=(3,))
t2 = threading.Thread(target=sing, kwargs={"num": 3})
6:创建守护线程:
方案一:
t1 = threading.Thread(target=sing,daemon=True)
方案二:
t1.setDaemon(True)
方案三:
t1.daemon = True
7:设置线程同步
t1.join()
8:锁的使用
创建锁:
mutex = threading.Lock()
上锁:
mutex.acquire()
解锁:
mutex.release()
线程和进程对比:
- 关系对比:
- 线程依附进程,有进程才有线程
- 一个进程默认有一个线程,也可以有多个线程
- 区别对比:
- 全局变量:
- 进程不能共享全局变量
- 线程可以共享全局变量,出现资源竞争问题,可以通过互斥锁和线程同步解决。
- 开销上:
- 创建进程的开销比创建线程的开销大
- 概念上:
- 进程是操作系统资源分配的单位
- 线程是cpu调度的单位
- 关系上:
- 线程依附进程存在,不能单独存在
- 稳定性上
- 多进程编程比单进程多线程编程稳定性更好
- 优缺点对比:
- 进程:优点(稳定性,可以使用多核)缺点(开销大)
- 线程:优点(开销小)缺点(不能使用多核)
2:多进程的使用:
三步走:导入包:import multiprocessing—>创建子进程:multiprocessing.Process(target=sing)—>启动子进程:
sing_process.start()
import multiprocessing
import time
# 跳舞任务
def dance():
for i in range(5):
print("跳舞中...")
time.sleep(0.2)
# 唱歌任务
def sing():
for i in range(5):
print("唱歌中...")
time.sleep(0.2)
if __name__ == '__main__':
# 创建跳舞的子进程
# group: 表示进程组,目前只能使用None
# target: 表示执行的目标任务名(函数名、方法名)
# name: 进程名称, 默认是Process-1, .....
dance_process = multiprocessing.Process(target=dance, name="myprocess1")
sing_process = multiprocessing.Process(target=sing)
# 启动子进程执行对应的任务
dance_process.start()
sing_process.start()
3:获取进程编号和父类进程编号:
# 创建一个子进程,在子进程中查看自己的进程编号,和父亲的编号
import multiprocessing
import time
import os
def test():
print("我是子进程:", multiprocessing.current_process())
print("我的进程名是: ", multiprocessing.current_process().name)
print("我的当前进程编号是: ", os.getpid())
print("我的父进程的编号是: ", os.getppid())
for i in range(5):
print("看我能活几轮...")
# 杀死我自己,9是杀死指令
os.kill(os.getpid(), 9)
def main():
p1 = multiprocessing.Process(target=test)
p1.start()
print("我是父进程:", multiprocessing.current_process())
print("我是父进程,我的进程名是: ", multiprocessing.current_process().name)
print("我是父进程,我的进程编号是: ", os.getpid())
if __name__ == '__main__':
main()
4:进程执行带有参数的任务:
import multiprocessing
import time
def sing(num, name):
for i in range(num):
print("我叫%s,我要唱我的第%d首歌" % (name, i+1))
time.sleep(1)
def dance(num, name):
for i in range(num):
print("我叫%s,我要跳我的第%d首舞" % (name, i+1))
time.sleep(1)
def main():
p1 = multiprocessing.Process(target=sing,args=(3,"小明"))
p2 = multiprocessing.Process(target=dance,kwargs={"num": 5, "name": "小红"})
p1.start()
p2.start()
if __name__ == '__main__':
main()
5:进程之间不共享全局变量:
# 思路:建立一个空数组,在两个进程中分别修改,看输出的情况
import multiprocessing
import time
def test1():
for i in range(5):
g_num.append(i)
print("我是子进程一,我的g_num: ",g_num)
def test2():
print("我是子进程二,我的g_num: ",g_num)
g_num = []
def main():
p1 = multiprocessing.Process(target=test1)
p2 = multiprocessing.Process(target=test2)
p1.start()
time.sleep(1)
p2.start()
print("我是主进程,我的g_num是: ", g_num)
if __name__ == '__main__':
main()
# 运行结果是:
# 我是子进程一,我的g_num: [0, 1, 2, 3, 4]
# 我是主进程,我的g_num是: []
# 我是子进程二,我的g_num: []
6:主进程会等待所有的子进程执行结束再结束
# 思路:让子进程花费比自己多的时间
import multiprocessing
import time
def test():
for i in range(5):
print("我是子进程,我正在执行......")
time.sleep(0.2)
def main():
p = multiprocessing.Process(target=test)
p.start()
time.sleep(0.5)
print("我是主进程,我要结束啦")
exit()
if __name__ == '__main__':
main()
# 运行结果:
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
# 我是主进程,我要结束啦
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
7:守护主进程以及子进程的销毁:
# 思路:设置子进程.daemon=True或者 子进程杀死自己
import multiprocessing
import time
def test():
for i in range(5):
print("我是子进程,我正在执行......")
time.sleep(0.2)
def main():
p = multiprocessing.Process(target=test)
#将子进程设置成守护主线程
# p.daemon=True
p.start()
time.sleep(0.5)
print("我是主进程,我要结束啦")
# 在主进程销毁之前杀死子进程
p.terminate()
exit()
if __name__ == '__main__':
main()
#
# 运行结果:
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
# 我是主进程,我要结束啦
二:线程:
1:定义:线程是CPU调度的基本单位
2:线程的基本使用:
import threading
import time
# 唱歌任务
def sing():
# 扩展: 获取当前线程
# print("sing当前执行的线程为:", threading.current_thread())
for i in range(3):
print("正在唱歌...%d" % i)
time.sleep(1)
# 跳舞任务
def dance():
# 扩展: 获取当前线程
# print("dance当前执行的线程为:", threading.current_thread())
for i in range(3):
print("正在跳舞...%d" % i)
time.sleep(1)
if __name__ == '__main__':
# 扩展: 获取当前线程
# print("当前执行的线程为:", threading.current_thread())
# 创建唱歌的线程
# target: 线程执行的函数名
sing_thread = threading.Thread(target=sing)
# 创建跳舞的线程
dance_thread = threading.Thread(target=dance)
# 开启线程
sing_thread.start()
dance_thread.start()
3:线程执行带有参数的任务:
# 思路,主线程向子线程中传递一些参数,在子线程中使用这些参数
import threading
import time
def dance(num,name):
for i in range(num):
print("我是%s,我在跳第%d个舞,欢迎观赏" % (name, i))
time.sleep(0.2)
def sing(num,name):
for i in range(num):
print("我是%s,我在唱第%d个歌,欢迎倾听" % (name,i))
time.sleep(0.2)
def main():
t1 = threading.Thread(target=dance, args=(5,"小红"))
# 注意:这里必须键和参数名字相同
t2 = threading.Thread(target=sing,kwargs={"num": 3,"name":"小绿"})
t1.start()
t2.start()
if __name__ == '__main__':
main()
# # 运行结果:
# 我是小红,我在跳第0个舞,欢迎观赏
# 我是小绿,我在唱第0个歌,欢迎倾听
# 我是小绿,我在唱第1个歌,欢迎倾听
# 我是小红,我在跳第1个舞,欢迎观赏
# 我是小绿,我在唱第2个歌,欢迎倾听
# 我是小红,我在跳第2个舞,欢迎观赏
# 我是小红,我在跳第3个舞,欢迎观赏
# 我是小红,我在跳第4个舞,欢迎观赏
4:线程之间执行没有顺序
# 思路:创建10个线程,分别打印
import threading
import time
def test():
# 为什么要休眠一秒??
time.sleep(1)
print("我是线程:",threading.current_thread().name)
def main():
# 因为循环创建线程,先初始化,再启动,可能的第一个和第二个初始化之间,第一个已经启动完成了。这就导致会顺序创建线程。
# 用睡眠堵塞每个进程,让他们几乎同一时间启动。
for i in range(10):
t1 = threading.Thread(target=test)
t1.start()
if __name__ == '__main__':
main()
5:主线程要等待所有子线程结束再结束
# 让子线程花费比主线程更多的时间,使用exit退出主线程
import threading
import time
def test():
for i in range(5):
print("我是子线程.....")
time.sleep(1)
print("我是子线程,我死啦")
def main():
t1 = threading.Thread(target=test)
t1.start()
time.sleep(1)
print("----我是主线程,我马上就死啦")
exit()
print("----我绝对死透了,你看不到我")
if __name__ == '__main__':
main()
# 运行结果:
# 我是子线程.....
# ----我是主线程,我马上就死啦
# 我是子线程.....
# 我是子线程.....
# 我是子线程.....
# 我是子线程.....
# 我是子线程,我死啦
6:守护主线程的三种方式:
import threading
import time
def test():
print("我是子线程,我要用3s")
time.sleep(3)
print("主线程没死,我就让你看到")
def main():
# 方法一:在创建子线程的参数中加上daemon=True
# t1 = threading.Thread(target=test, daemon=True)
t1 = threading.Thread(target=test)
# 方法二:使用子线程的setDaemo方法
# t1.setDaemon(True)
# 方法三:设置子线程的daemon参数=True
t1.daemon = True
t1.start()
time.sleep(1)
if __name__ == '__main__':
main()
7:线程之间共享全局变量:
# 思路:对于一个数据,一个线程向里面写数据,一个线程读数据,看能不能读到另外一个线程写入后的数据
import threading
import time
def num_add():
for i in range(4):
g_num.append(i)
print("我是子线程一中的g_num: ",g_num)
def num_read():
print("我是子线程二中的g_num: ", g_num)
g_num = []
def main():
t1 = threading.Thread(target=num_add)
t2 = threading.Thread(target=num_read)
t1.start()
# 保证子线程一执行完成
time.sleep(1)
t2.start()
print("我是主线程中的g_num: ", g_num)
if __name__ == '__main__':
main()
# #运行结果
# 我是子线程一中的g_num: [0, 1, 2, 3]
# 我是子线程二中的g_num: [0, 1, 2, 3]
# 我是主线程中的g_num: [0, 1, 2, 3]
8:线程之间共享全局变量存在的问题:
# 思路:如果一个线程给一个全局变量增加100000次,另一个也进行,最后的结果不会是200000,而是在100000到200000之间。
import threading
import time
def num_add1():
for i in range(1000000):
global g_num
g_num += 1
print("当子线程一只想结束g_num是:", g_num)
def num_add2():
for i in range(1000000):
global g_num
g_num += 1
print("当子线程二只想结束g_num是:", g_num)
g_num = 0
def main():
t1 = threading.Thread(target=num_add1)
t2 = threading.Thread(target=num_add2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
# 运行结果:
# 当子线程一只想结束g_num是: 1280374
# 当子线程二只想结束g_num是: 1589925
9:共享变量的解决方案—同步
# 思路:让一个线程执行完,另一个线程再执行
import threading
import time
def num_add1():
for i in range(1000000):
global g_num
g_num += 1
print("当子线程一只想结束g_num是:", g_num)
def num_add2():
for i in range(1000000):
global g_num
g_num += 1
print("当子线程二只想结束g_num是:", g_num)
g_num = 0
def main():
t1 = threading.Thread(target=num_add1)
t2 = threading.Thread(target=num_add2)
t1.start()
# 让子线程一执行结束再开启子线程二
t1.join()
t2.start()
if __name__ == '__main__':
main()
#
# 运行结果:
# 当子线程一只想结束g_num是: 1000000
# 当子线程二只想结束g_num是: 2000000
10:共享变量的解决方案—互斥锁
# 思路:让可能出现资源竞争的地方所上锁
import threading
# 1:创建锁
lock = threading.Lock()
def num_add1():
# 2:出现资源竞争的地方所上锁
lock.acquire()
for i in range(1000000):
global g_num
g_num += 1
print("当子线程一只想结束g_num是:", g_num)
# 3:执行完释放锁
lock.release()
def num_add2():
# 相同地方上锁
lock.acquire()
for i in range(1000000):
global g_num
g_num += 1
print("当子线程二只想结束g_num是:", g_num)
# 相同地方解锁
lock.release()
g_num = 0
def main():
t1 = threading.Thread(target=num_add1)
t2 = threading.Thread(target=num_add2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
#
# 运行结果:
# 当子线程一只想结束g_num是: 1000000
# 当子线程二只想结束g_num是: 2000000
# 问题:为啥不在g_num += 1的前后上锁,而是在循环前后上锁,因为频繁开锁和解锁会降低代码执行效率
# 导致程序运行缓慢
11:死锁:一直等待对方释放锁的情景就是死锁
import threading
lock = threading.Lock()
def get_value(index):
lock.acquire()
if index >= len(g_num):
print("数组下标越界啦")
lock.release()
return
value = g_num[index]
print(value)
lock.release()
g_num = [1,2,3]
def main():
for i in range(30):
t1 = threading.Thread(target=get_value, args=(i,))
t1.start()
if __name__ == "__main__":
main()
浙公网安备 33010602011771号