进程互斥锁
让并发变成串行,牺牲了执行效率,保证了数据安全。在程序并发执行时,需要修改数据时使用
import json
import time
from multiprocessing import Process
from multiprocessing import Lock
#查看余票
def serch(user):
with open('data.txt','r',encoding='utf-8') as f:
dic=json.load(f)
print(f'用户{user}查看了余票,还剩{dic.get("ticket_num")}')
#开始抢票
def buy(user):
with open('data.txt','r',encoding='utf-8') as f:
dic=json.load(f)
time.sleep(1)
if dic.get("ticket_num")>0:
dic['ticket_num']-=1
with open('data.txt', 'w', encoding='utf-8') as f:
json.dump(dic,f)
print(f'用户{user}抢票成功')
else:
print(f'用户{user}抢票失败')
def run(user,mutex):
#并发,异步执行
serch(user)
#串行,同步执行
mutex.acquire()#加锁
buy(user)
mutex.release()#释放锁
if __name__ == '__main__':
#调用Lock()类得到一个锁对象
mutex=Lock()
for i in range(10):
#并发开启10个子进程
p=Process(target=run,args=(f'用户{i}',mutex))
p.start()
'''用户用户0查看了余票,还剩1
用户用户1查看了余票,还剩1
用户用户2查看了余票,还剩1
用户用户3查看了余票,还剩1
用户用户9查看了余票,还剩1
用户用户6查看了余票,还剩1
用户用户4查看了余票,还剩1
用户用户7查看了余票,还剩1
用户用户8查看了余票,还剩1
用户用户5查看了余票,还剩1
用户用户0抢票成功
用户用户1抢票失败
用户用户2抢票失败
用户用户3抢票失败
用户用户9抢票失败
用户用户6抢票失败
用户用户4抢票失败
用户用户7抢票失败
用户用户8抢票失败
用户用户5抢票失败'''
队列:先进先出
相当于内存中产生一个队列空间,可以存放多个数据,但数据的顺序时由先进去的排在前面。
堆栈:先进后出
from multiprocessing import Queue
#调用队列类,实例化队列对象 q
q=Queue(5)#若传参,队列中可以存放5个数据
# q=Queue()#若不传参,队列中可以存放无限大的数据,前提硬件能跟的上
#put添加数据,若队列中的数据满了,则卡住
q.put(1)
print('进入数据1')
q.put(2)
print('进入数据2')
q.put(3)
print('进入数据3')
q.put(4)
print('进入数据4')
q.put(5)
print('进入数据5')
# q.put(6)
# print('进入数据6')
#查看队列是否满了
print(q.full())#True
#添加数据,若队列满了,则会报错
# q.put_nowait(6)
#q.get():获取数据遵守“先进先出”,若队列中无数据可取,也会卡住
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
#get_nowait:获取数据,队列中若没有,则会报错
# print(q.get_nowait())
#判断队列是否为空
print(q.empty())#True
q.put(6)
print('进入数据6')
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('主进程')
'''主进程
进程1开始添加数据到队列中
进程2从队列中获取数据数据hello'''
生产者和消费者
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=('nick', 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('主进程')
'''用户tank开始制作了('油条', 0)
用户坦克开始制作了('烧饼', 0)
用户nick开始吃('油条', 0)
用户nick开始吃('烧饼', 0)
用户tank开始制作了('油条', 1)
用户nick开始吃('油条', 1)
用户坦克开始制作了('烧饼', 1)
用户jason开始吃('烧饼', 1)
用户tank开始制作了('油条', 2)
用户nick开始吃('油条', 2)
用户坦克开始制作了('烧饼', 2)
用户jason开始吃('烧饼', 2)
用户tank开始制作了('油条', 3)
用户nick开始吃('油条', 3)
用户坦克开始制作了('烧饼', 3)
用户jason开始吃('烧饼', 3)
用户tank开始制作了('油条', 4)
用户nick开始吃('油条', 4)
用户坦克开始制作了('烧饼', 4)
用户jason开始吃('烧饼', 4)
用户tank开始制作了('油条', 5)
用户nick开始吃('油条', 5)
用户坦克开始制作了('烧饼', 5)
用户jason开始吃('烧饼', 5)
用户tank开始制作了('油条', 6)
用户nick开始吃('油条', 6)
用户坦克开始制作了('烧饼', 6)
用户jason开始吃('烧饼', 6)
用户tank开始制作了('油条', 7)
用户nick开始吃('油条', 7)
用户坦克开始制作了('烧饼', 7)
用户jason开始吃('烧饼', 7)
用户tank开始制作了('油条', 8)
用户nick开始吃('油条', 8)
用户坦克开始制作了('烧饼', 8)
用户jason开始吃('烧饼', 8)
主进程'''
线程
1.什么是线程
线程与进程都是细腻单位,目的是为了更好的描述某种事物
-进程:资源单位
-线程:执行单位
开启一个进程,一定会有一个线程,线程才是真正执行者
2.为什么要使用线程
节省内存资源
-开启进程:
1)开辟一个名称空间,每开启一个进程都会占用一份内存资源
2)会自带一个线程
-开启线程:
1)一个进程可以开启多个线程
2)线程开销远小于进程
注意:线程不能实现并行,线程只能实现并发,进程可以实现并行
比喻:内存就像一个工厂,子进程就好像一个工厂车间,线程就像车间内的流水线
线程之间数据是共享的
from threading import Thread
import time
#开启线程方式1
def task():
print('线程开启')
time.sleep(1)
print('线程结束')
if __name__ == '__main__':
#调用Thread线程类实例化得到线程对象
t=Thread(target=task)
t.start()
'''线程开启
线程结束'''
# 开启线程方式2
class MyThread(Thread):
def run(self):
print('线程开启')
time.sleep(1)
print('线程结束')
if __name__ == '__main__':
t=MyThread()
t.start()
'''线程开启
线程结束'''
线程对象的属性
from threading import Thread
from threading import current_thread
import time
def task():
print(f'线程开启{current_thread().name}')
time.sleep(2)
print(f'线程结束{current_thread().name}')
if __name__ == '__main__':
t=Thread(target=task)
# t.daemon=Thread#父线程结束子线程也要结束
t.start()
print(t.is_alive())#判断子线程是否存活
'''线程开启Thread-1
True
线程结束Thread-1'''
对象互斥锁
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)
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()
print(n)