进程互斥锁:
from multiprocessing import Lock
让并发变成串行,牺牲了执行效率,保证了数据安全。
在程序并发执行时,需要修改数据时使用。
模拟抢票实例:
data:
"ticket_num":3
代码:
import json
import time
from multiprocessing import Process
from multiprocessing import Lock
def search(user): # 查看余票功能
with open('data.txt', 'r', encoding='utf8') as f: # 打开数据文件
dic = json.load(f)
print(f'用户{user}查看余票,还剩{dic.get("ticket_num")}张')
def buy(user): # 余票数据修改功能
with open('data.txt', 'r', encoding='utf8')as f: # 再次打开是为了打开最新数据
dic = json.load(f) # 拿到车票相关数据
time.sleep(0.2) # 模拟网络延时
if dic.get("ticket_num") > 0: # 还有余票就购票,余票数量减1
dic['ticket_num'] -= 1
with open('data.txt', 'w', encoding='utf8')as f:
json.dump(dic, f) # 保存车票相关数据
print(f'用户:{user}抢票成功!')
else:
print(f'用户:{user}抢票失败!')
def run(user, mutex): # 抢票功能
search(user) # 调用查看余票功能
mutex.acquire() # 加锁
buy(user) # 抢票功能
mutex.release() # 解锁
if __name__ == '__main__':
mutex = Lock() # 调用Lock()得到一个锁对象
for i in range(10): # 设置10个用户来同时抢票
# 调用Process得到一个p对象
p = Process(target=run, args=(f'用户{i}', mutex))
p.start() # 创建子进程
队列:先进先出
相当于内存中产生一个队列空间,可以存放多个数据,但数据的顺序是由先进的排在前面
from multiprocessing import Queue
# 调用队列类,实例化队列对象 q
q = Queue(5) # 若传参队列中可以存放5个数据
# q1 = Queue() # 若不传参,队列中可以存放无限大的数据,前提硬件能更得上
# put添加数据,若队列中的数据满了,则卡住
q.put(1)
# 查看队列是否满了
print(q.full()) # True
# 添加数据,若队列满了,则会报错
q.put_nowait(6)
# q.get(): 获取的数据遵循 "先进先出",若队列中无数据可取,也会卡住
print(q.get())
get_nowait: # 获取数据,队列中若没有,则会报错
print(q.get_nowait())
# 判断队列是否为空
print(q.empty()) # False
堆栈:先进后出
ICP: 进程间通信
进程间数据时相互隔离的,若想实现进程间通信,可以利用队列
from multiprocessing import Process
from multiprocessing import Queue
def test1(q):
data = 'test1'
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(5):
data = food, i
msg = f'用户{name}开始制作{data}'
print(msg)
q.put(data)
time.sleep(0.2)
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=('json', '油条', q))
p2 = Process(target=producer, args=('allen', '红烧肉', q))
c1 = Process(target=consumer, args=('jack', q))
c2 = Process(target=consumer, args=('wills', q))
p1.start()
p2.start()
c1.daemon = True
c2.daemon = True
c1.start()
c2.start()
p2.join()
print('主进程')
线程:
什么是线程
线程与进程都是虚拟单位,目的是为了更好地描述事物
进程是资源单位
线程是执行单位
开启一个进程,一定会产生一个线程,线程才是真正的执行者
为什么要使用线程
节省内存资源
开启进程:
1、开辟一个名称空间,每开启一个进程都会占用一份内存资源
2、会自动生成一个线程
开启线程:
1、一个进程可以开启多个线程
2、线程的开销远小于进程
注意:进程可以实现并行,线程不能实现并行,线程只能实现并发,
线程之间的数据是共享的
线程的两种创建方式:
方式一:
from threading import Thread
import time
def task():
print('线程开启')
time.sleep(1)
print('线程结束')
if __name__ == '__main__':
t = Thread(target=task)
t.start()
方式二:
from threading import Thread
import time
class MyThread(Thread):
def run(self):
print('线程开启')
time.sleep(1)
print('线程结束')
if __name__ == '__main__':
t = MyThread()
t.start()
线程互斥锁:
from threading import Thread, Lock
mutex = Lock()
mutex.acquire() # 上锁
······
mutex.release() # 解锁