进程与线程
操作系统/进程
程序
1. 程序是什么?
一堆文件
2. 进程是什么?
进程就是一个正在执行的文件/程序
3. 进程被谁执行?
CPU最终运行你的程序
操作系统调度作用,将你的磁盘上的程序加载到内存 , 然后交由CPU去处理 , 一个CPU正在运行的一个程序 , 就叫开启了进程
操作系统
1. 操作系统的定义
操作系统是存在于硬件和软件之间, 管理 , 协调 , 控制软件和硬件
2. 操作系统的作用
1. 把复杂的硬件操作 , 封装成简单清晰的接口
- 合理调度分配多个进程与CPU的关系
进程介绍
- 串行: 所有的进程 , CPU一个一个的解决
- 并发: 单个CPU , 同时执行多个进程(来回切换的运行)
- 并行: 多个CPU , 真正的同时运行多个进程
- 阻塞: 例如 I/O
进程的创建
开启进程 : 内存中开空间 , 加载资源与数据应 , 调用CPU执行 , 可能还会使用这个空间的资源
由主进程创建一个或多个子进程 , 第一个主进程是操作系统
py文件中 开启新的子进程 , 只是一个新的入口 , 将全局的所有数据复制一份给子进程
进程的id
- 终端: tasklist | findstr appname
- pycharm中 os.getpid() os.getppid()
join 阻塞
join阻塞的是主进程 自适应sleep
守护进程
daemon 守护进程 主程序死亡子程序跟着死亡
## 守护进程
from multiprocessing import Process
x = 1000
def task():
global x
print(x)
x = 2
print(id(x))
test() ##@2
def test():
print('我被执行了')
if __name__ == '__main__':
p = Process(target=task) ##@2
p.daemon() = True #先声明
p.start() # 再开启
print(id(x))
from multiprocessing import Process
import time
## 并发 join
def task(name,s):
time.sleep(s)
print(name)
def test():
print(11111)
if __name__ == '__main__':
t1 = time.time()
## 并发
obj_l = []
for i in range(1,4):
p = Process(target=task,args=('x'*i,i))
p.start()
obj_l.append(p)
for func in obj_l:
func.join()
print(time.time()-t1)
print('主进程')
## 子进程开启时 , 会复制主进程的内容 看@2
from multiprocessing import Process
x = 1000
def task():
global x
print(x)
x = 2
print(id(x))
test() ##@2
def test():
print('我被执行了')
if __name__ == '__main__':
p = Process(target=task) ##@2
p.start()
p.terminate() ## 终止进程
p.is_alive() ## 查看进程是否活着
print(id(x))
僵尸进程
僵尸进程是当子进程比父进程先结束 , 而父进程没有回收子进程 , 释放子进程占用的资源 , 此时子进程将成为一个僵尸进程
孤儿进程
如果父进程先退出 , 子进程被init接管 , 这时子进程为孤儿进程
进程通信
- 进程在内存级别不允许通信
- 可以同时操作一个文件 , 多进程抢占同一资源时 , 保证结果正确 , 公平性竞争 , 必须保证串行 , 并且上锁
- 进程通信要用队列 , FIFO
互斥锁
from multiprocessing import Process
from multiprocessing import Lock
import time
## 互斥锁 一锁一解 遇见阻塞 , cpu还是会切换进程, 但是遇到锁了 , 发现锁被占用
def task(lock):
lock.acquire()
time.sleep(2)
print(11)
lock.release()
def task2(lock):
lock.acquire()
time.sleep(1)
print(222)
lock.release()
if __name__ == '__main__':
lock = Lock()
p1= Process(target=task,args=(lock,))
p2 = Process(target=task2,args=(lock,))
p1.start()
p2.start()
队列 Queue
q = Queue(maxsize = 3)
q.put(1)
q.put('str')
q.put(obj)
q.put(xxx,block = True) # block 默认为True 队列长度是3 再放入一个就会阻塞
q.get()
q.get()
q.get(timeout = 3) # 取数据 , 也有block 用法相同 , timeout表示最长阻塞时间
生产者消费者模型
合理的调控 , 多个进程生产数据与提取数据 , 中间数据使用队列Queue
对生产者消费者解耦 , 平衡了生产力和消费力 , 多用于解决并发的问题
线程
进程主要任务 : 开启空间 , 加载数据 , 静态的
线程: 执行代码 , 动态的
线程和进程的对比
- 开启进程 : 开销非常大 ; 开启线程开销非常小
- 开启多进程速度慢 , 开启多线程速度快
- 进程之间理论数据不能共享 , 同一进程下的线程是可以数据共享的
# threading 方法
from threading import Thread
import threading
def task():
print(11)
def task2():
print(22)
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task2)
t1.start()
t2.start()
print (threading.current_Thread) # 当前线程
print (active_count()) # 当前存活线程
print(threading.enumerate()) # 枚举线程
守护线程
与守护进程不同 , 守护线程要等到所有线程(非守护线程)结束后才结束
递归锁 一把锁 RLock
相同线程可以重复上锁 , 解锁也要解相应的次数
## 解决死锁的问题
from threading import Thread
from threading import RLock
import time
rlock = RLock()
class MyThread(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
rlock.acquire()
print(f'{self.name}获取的了rlock')
rlock.acquire()
print(f'{self.name}获取的了rlock')
rlock.release()
print(f'{self.name}释放了rlock')
rlock.release()
print(f'{self.name}释放了rlock')
def f2(self):
rlock.acquire()
print(f'{self.name}获取的了rlock')
time.sleep(1)
rlock.acquire()
print(f'{self.name}获取的了rlock')
rlock.release()
print(f'{self.name}释放了rlock')
rlock.release()
print(f'{self.name}释放了rlock')
if __name__ == '__main__':
for i in range(3):
t = MyThread()
t.start()
信号量
一个锁 , 多个坑 , 可允许多个线程同时进入
from threading import Semaphore
from threading import Thread
import time
import random
slock = Semaphore(5)
def task(i):
slock.acquire()
print(f'{i},进入')
time.sleep(random.randint(1,3))
slock.release()
if __name__ == '__main__':
for i in range(20):
t = Thread(target=task,args=(i,))
t.start()