一、多任务
1. 多任务
在同一时间段,同时执行多个任务
2. 并发
任务数量 > CPU核心数量,CPU核心在同一时间段交替执行
3. 并行
任务数量 < CPU核心数量,同一时刻执行多个任务(指多核情况下)
二、进程
1.概念:
进程是操作系统调度和分配资源的最小单位
2.特点
- 程序开启后默认开启一个进程
- 开启多个进程执行任务效率更高
- 开启进程后默认开启一个主线程
3.实现多进程
任务调用单位:函数
# 1. 导入进程包
import multiprocessing
# 2. 通过进程类创建进程对象(func是函数名,可省略:name进程名,group进程组)
def func():
print("music.....")
p = multiprocessing.Process(target=func, name=proc_name, group=None)
# 3. 启动进程
p.start()
4. 面向对象实现
import multiprocessing
class MyProcess(multiprocessing.Process):
def __init__(self):
super().__init__()
def music(self):
print('music...')
def run(self) -> None:
self.music()
m = MyProcess()
m.start()
5. 进程传递参数
- 通过元组 multiprocessing.Process(target=func, args=(3,))
- 通过dict multiprocessing.Process(target=func, kwargs={“num”: 3})
6. 获取进程编号
- 父进程:创建当前进程的进程,称为父进程;
-
获取当前进程编号
# 获取当前进程编号 os.getpid() # 查看进程名 multiprocessing.current_process().name
-
获取父进程编号
os.getppid()
7. 进程间不共享全局变量
-
创建子进程会对主进程资源进行拷贝
-
进程join:把进程原来的并行执行改成串行
import multiprocessing import time l = [] def write_data(): for i in range(10): l.append(i) print(l) def read_data(): print(l) if __name__=="__main__": print('主进程开始!') p1 = multiprocessing.Process(target=write_data) p2 = multiprocessing.Process(target=read_data) p1.start() # join 将原来的并行改为串行,即将p1执行完之后,再进行后续操作 p1.join() # time.sleep(1) p2.start() p2.join() print('主进程结束!')
-
主进程会等到所有子进程结束后再结束
8. 主进程和子进程的执行顺序
-
为了保证子进程能正常运行,主进程会等到所有子进程执行结束后再销毁
-
如果想要主进程执行结束后结束子进程,可以通过守护进程或者手动销毁子进程
# 设置守护主进程的方式: 子进程对象.daemon = True # 销毁子进程的方式 子进程对象.terminate()
9. 进程相关Linux命令
```
# 获取进程信息
ps -ef | grep python
ps -aux | grep python
# 杀死进程
kill -9 进程号
```
三、线程
1. 多线程创建
# 1.导入模块
import threading
# 2. 创建thread
t = threading.Thread(target=func, args=(1,), kwargs={})
# 3. 开启start
t.start()
2. 多线程传参
- args: 以元组的方式(必须和函数的参数顺序一致)
- kwargs: 以字典的方式
3. 线程的执行顺序
- 需要主线程结束,停止子线程
- 线程间执行是无序的,是由CPU调度决定的
# 守护线程:主线程执行完毕,子线程也结束
t = threading.Thread(target=func, daemon=True)
# 线程串行执行
t.join()
# 获取当前线程的名称
threading.current_thread().name
4.线程间共享全局变量
import threading
import time
l = []
def write_data(num):
for i in range(num):
l.append(i)
print('write_data:', l)
def read_data(count):
# print(count)
print('read_data:', l)
if __name__ == '__main__':
wp = threading.Thread(target=write_data, args=(10,))
rp = threading.Thread(target=read_data, kwargs={'count': 20})
wp.start()
time.sleep(1)
rp.start()
print('主进程结束')
四、锁
1. 线程间访问全局变量错误
原因:操作非原子性(不是一步就能搞定),例如 a+=1
解决方案:把操作进行同步,使用同步锁
2.互斥锁
# 1.创建锁
mutex = threading.lock()
# 2.上锁
mutex.acquire()
# 3. 释放锁
mutex.release()
3.死锁
申请和释放锁是成对出现的,如果线程中只申请锁,不释放锁,就会产生死锁,程序会停止运行
五、线程VS进程
- 进程是系统分配和调度资源的最小单位,线程是CPU执行的最小单位
- 创建进程消耗资源大,线程消耗小
- 进程不能访问全局变量,线程可以
- 优先使用线程,其次考虑进程
- 线程不能独立运行,必须依附于进程而存在的,一个进程默认有一个线程,进程可以创建多个线程
- 进程可以使用多核,线程中不能使用多核(特指Python的CPython解释器)
六、进程通信方式
- 管道
- 消息队列
- 共享内存
- 信号量
- Socket