进程:资源分配的最小单位(QQ、微信)
多进程:程序自动创建主进程;自己创建子进程
1. 导入进程模块
import multiprocessing
2. 创建进程对象
coding_process = multiprocessing.Process(target=coding) # target=函数名 music_process = multiprocessing.Process(target=music)
3. 启动进程
对比:coding_process.start() music_process.start()
1. 主进程
import time def coding(): for i in range(3): print("coding...") time.sleep(0.2) def music(): for i in range(3): print("music...") time.sleep(0.2)coding()
musci()
结果:
2. 多进程
# 代码只能作为脚本直接执行,import 到其他脚本中是不会被执行的
if __name__ == '__main__':
# 创建进程对象
coding_process = multiprocessing.Process(target=coding) # target=函数名
music_process = multiprocessing.Process(target=music)
# 启动进程
coding_process.start()
music_process.start()
结果:
二、进程(参数)args:以元组方式给执行任务传参 args=(a, b) #a、b为两个参数
kwargs: 以字典方式给执行任务传参 kwargs={} #
三、进程编号 os.getppid() 获取当前进程编号 os.getppid() 获取当前父进程编号import os
def work(): # 定义函数
print("work进程编号:", os.getpid())
print("work父进程编号:", os.getppid())
def coding():
print("coding %d" % os.getpid())
print("coding %d" % os.getppid()) # 父进程
for i in range(3):
print("coding...")
time.sleep(0.2)
def music():
print("music %d" % os.getpid())
print("music %d" % os.getppid() # 父进程
for i in range(3):
print("music...")
time.sleep(0.2)
四、 进程间不共享全局变量 五、主进程、子进程结束顺序if __name__ == '__main__': #主进程 print("music %d" % os.getpid()) print("music %d" % os.getppid()) # 创建进程对象 coding_process = multiprocessing.Process(target=coding) # target=函数名 music_process = multiprocessing.Process(target=music) #2为实参 # 启动进程 coding_process.start() music_process.start()说明:coding和music是由主进程创建的子进程
主进程会等所有子进程执行完毕后再执行
守护子进程:主进程执行完毕后不管子进程是否执行完毕都会销毁。
work_process.daemon = True
手动销毁子进程: work_process.terminate()
if __name__ == "__main__":
# 创建子进程
work_process = multiprocessing.Process(target=work)
1) # 设置守护主进程
work_process.daemon = True
# 启动子进程
work_process.start()
# 延时1秒
time.sleep(1)
2) # 手动结束
work_process.terminate()
print("主进程执行完毕")
六、线程
多线程是实现多任务的一种方式
程序执行的最小单位,一个进程里最少有一个进程来执行
同一进程的多个线程共享所拥有的的全部资源
线程创建步骤:1. 导入线程模块
import threading
2. 通过线程类创建线程对象
线程对象=threading.Thread(target=任务名) # 函数名
3. 启动线程执行任务
线程对象.start()
1. 线程(同进程)线程执行无序dance = threading.Thread(target=sing, kwargs={"count": 5})
sing = threading.Thread(target=sing, arg(5, ))
import threading
import time
def task():
time.sleep(1)
# threading.current_thread() 当前线程 .name 获取线程名字
print(f"当前的线程是 {threading.current_thread().name}")
if __name__ == '__main__':
print(f"当前的主线程: {threading.current_thread().name}")
# 多个线程
for _ in range(5): # _也是变量
# 创建子线程
sub_thread = threading.Thread(target=task)
sub_thread.start()
结果
2. 主线程会等待所有子线程运行结束后再执行 3. 线程之前共享全局变量 1)资源竞争:当多个线程调用一个全局变量资源时,全局变量资源不断的被修改,调用过程存在资源竞争解决方法: 采用全局变量锁,每次线程调用后,将该资源上锁,不允许再被调用,只有调用结束后打开锁,保证全局变量资源的安全。
# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()
注意:如果aquire调用前已有互斥锁,则会堵塞,等待解锁后,才会调用
import threading
# 定义全局变量
g_num = 0
# 创建互斥锁
lock = threading.Lock()
# 循环一次给全局变量加1
def sum_1():
# 上锁
lock.aquire()
for i in range(1000000):
global g_num # 全局变量
g_num += 1
print("sum1:", g_num)
#释放锁
lock.release()
# 循环一次给全局变量加1
def sum_2():
# 上锁
lock.aquire()
for i in range(1000000):
global g_num # 全局变量
g_num += 1
print("sum2:", g_num)
#释放锁
lock.release()
if __name__ == '__main__':
# 创建两个线程
first_thread = threading.Thread(target=sum_num1)
second_thread = threading.Thread(target=sum_num2)
# 启动线程
first_thread.start()
second_thread.start()
总结:
1. 互斥锁可以保证多个线程访问同一个全局变量时不会出现错误
2. 加上互斥锁后,多任务变为单任务,性能下降
3. 互斥锁没使用好容易出现死锁情况
2)死锁一直等待对方释放锁的情景就是死锁
死锁会造成程序无法响应
例如:线程A的互斥锁未释放就让线程B的互斥锁上锁,等待资源释放
解决方案:
- 程序设计时要尽量避免(银行家算法)
- 添加超时时间等
银行家算法的核心思想:每次资源分配前判断此次分配是否会导致系统进入不安全状态,以此来决定是否答应资源分配请求
总结关系:
1. 线程是依附在线程里的,没有进程就没有线程
2. 一个进程默认提供一条线程,进程可以创建多个线程
对比:
1. 进程之间不共享全局变量
2. 线程之间共享全局变量,但注意资源竞争问题,解决方法是互斥锁,但要注意死锁
3. 创建线程资源开销比创建线程资源开销大
4. 进程是操作系统分配资源的基本单位,线程是CPU调度的基本单位
优缺:
进程:多核,资源开销大
线程:不能多核,资源开销小



