进程互斥锁
进程间数据不共享,但是共享同一套文件系统,
互斥锁:让并发变成串行,牺牲了执行效率,保证了数据安全
- 应用:在程序并发执行时,需要修改数据时使用
# data(json文件) {"target":1} # 模拟抢票功能.py import json import time from multprocessing import Process from multprocessing import Lock # 查看余票 def search(user): # 打开json文件查看余票 with open('data','r',encoding = 'utf-8')as f: dic = json.load(f) print(f'{user}查看余票:{dic.get("ticket")}') def buy(user): # 先打开车票数据 with open('data','r',encoding = 'utf-8')as f: dic = json.load(f) # 模拟网络延迟 time.sleep(1) # 若有票,修改data数据 if dic.get("ticket") > 0: dic['ticket'] -= 1 with open('data','w',encoding = 'utf-8')as f: json.dump(dic,f) print(f'{user}抢票成功') def run(user,mutex): # 并发:异步执行 search(user) # 加锁 mutex.acquire() # 串行:同步执行 buy(user) # 释放锁 mutex.release() if __name__ == '__main__': mutex = Lock() for i in range(10): p = Process(target = run,args = (f'用户{i}',)) p.start()
队列和堆栈
队列
相当于内存中的一个队列空间,可以存放多个数据,遵循“先进先出” (管道+锁)
堆栈
遵循“先进后出”
from multprocessing import Queue # 调用队列类实例化队列对象 q = Queue(3) # 参数代表队列中存放的参数数量,默认无限大 # q.put:添加数据,超过数量限制就会卡在哪里 q.put(1) q.put(2) q.put(3) # q.put_nowait:添加数据,超过数量限制报错 q.put_nowait(4) # q.get:获取的数据遵循“先进先出”,没有即卡住 print(q.get()) print(q.get()) print(q.get()) print(q.get()) # get_nowait:获取数据,队列中没有,则会报错 print(q.get_nowait()) # q.full:判断队列是否满了 print(q.full()) # q.empty:判断队列是否为空 print(q.empty:()) # False
进程间通信(IPC)
进程间数据是相互隔离的,若想实现进程间通信,可以利用队列
from multiprocessing import Process from multiprocessing import Queue def test1(q): data = '数据hello' q.put(data) print('进程1开始添加数据到队列中..') def test2(q): data = q.get() print(f'进程2从队列中获取数据{data}') if __name__ == '__main__': q = Queue() p1 = Process(target=test1, args=(q, )) p2 = Process(target=test2, args=(q, )) p1.start() p2.start() print('主')
生产者和消费者模型
通过队列的存储调用作为缓冲来解决
from multiprocessing import Queue, Process import time # 生产者 def producer(name, food, q): # 生产名, 食物, 队列 for i in range(9): data = food, i msg = f'用户{name}开始制作{data}' print(msg) q.put(data) time.sleep(0.1) # 消费者 def consumer(name, q): while True: data = q.get() if not data: break print(f'用户{name}开始吃{data}') if __name__ == '__main__': q = Queue() # 创造生产者 p1 = Process(target=producer, args=('tank', '油条', q)) p2 = Process(target=producer, args=('华农兄弟', '竹鼠', q)) # 生产消费者 c1 = Process(target=consumer, args=('egon', q)) c2 = Process(target=consumer, args=('jason', q)) p1.start() p2.start() c1.daemon = True c2.daemon = True c1.start() c2.start() p2.join() print('主')
线程
什么是线程
线程和进程都是虚拟单位,为了更好的描述某种事物
进程:资源单位
线程:执行单位
为什么使用线程
节省内存资源
- 开启进程
- 开辟一个名称空间,每开辟一个进程都会占用一份内存资源
- 每个进程会自带一个线程
- 开启线程
- 一个进程可以开启多个线程
- 线程的开销远小于进程
注意:线程不能实现并行,线程只能实现并发,进程可以实现并行
怎么开启线程
from threading import Thread import time # 开启线程方式1 def task(): print('thread start') time.sleep(1) print('thread end') t = Thread(target = task) t.start() # 开启线程方式2 class MyThread(Thread): def run(self): print('thread start') time.sleep(1) print('thread end') t = MyThread() t.start()
线程对象的属性
- Thread实例对象的方法
- isAlive():返回线程是否存在
- getName():返回线程名
- setName:设置线程名
- threading模块提供的方法
- currentThread().name:返回线程名
- activeCount():返回正在运行的线程数量
线程互斥锁
线程之间数据共享
# 如果不加互斥锁,因为线程并发运行,会导致每个线程同一时间获得的都是100, from threading import Thread, Lock import time mutex = Lock() n = 100 def task(i): print(f'线程{i}启动...') global n # mutex.acquire() temp = n time.sleep(0.1) # 一共等待10秒 n = temp-1 print(n) # mutex.release() if __name__ == '__main__': t_l=[] for i in range(100): t = Thread(target=task, args=(i, )) t_l.append(t) t.start() for t in t_l: t.join() # 100个线程都是在100-1 print(n)