Py004-01-06互斥锁

互斥锁

多个进程直接虽然数据不共享,但是它们共享同一套文件系统(或者同一个打印终端)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from multiprocessing import Process
import time

def task(name):
print('%s 1'%name)
time.sleep(1)
print('%s 2'%name)
time.sleep(1)
print('%s 3' % name)

if __name__ == '__main__':
# args传递的参数必须是元组的形式
for i in range(3):
p = Process(target=task, args=('子进程%s'%i,))
p.start()

print('主进程。。。。')


'''
主进程。。。。
子进程0 1
子进程1 1
子进程2 1
子进程0 2
子进程1 2
子进程2 2
子进程0 3
子进程1 3
子进程2 3
此时数据发生错乱,三个进程都占据打印终端的输出,这样数据容易出现问题
'''

互斥锁(来把锁)

  • 从multiprocessing引入Lock
  • 初始化锁 mutex = Lock()
  • 给子进程的触发函数传入锁对象mutex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from multiprocessing import Process,Lock
import time

def task(name,mutex):
mutex.acquire()
print('%s 1'%name)
time.sleep(1)
print('%s 2'%name)
time.sleep(1)
print('%s 3' % name)
mutex.release()

if __name__ == '__main__':
# args传递的参数必须是元组的形式
for i in range(3):
mutex=Lock()
p = Process(target=task, args=('子进程%s'%i,mutex))
p.start()

print('主进程。。。。')

'''
主进程。。。。
子进程0 1
子进程1 1
子进程2 1
子进程0 2
子进程1 2
子进程2 2
子进程0 3
子进程1 3
子进程2 3
'''

模拟抢票

多个进程共享同一文件,我们可以把文件当数据库,用多个进程模拟多个人执行抢票任务

新建文件db.txt的内容为:{“count”:1}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from multiprocessing import  Process
import json
import time

def search(name):
time.sleep(1) # 模拟网络延迟
dic = json.load(open('db.txt',encoding='utf-8'))
print('<%s>查看剩余票数[%s]'%(name,dic['count']))

def get(name):
time.sleep(1)
dic = json.load(open('db.txt', encoding='utf-8'))
if dic['count']>0:
dic['count']-=1
time.sleep(3)
json.dump(dic,open('db.txt','w',encoding='utf-8'))
print('<%s 购票成功>'%name)

def task(name):
search(name)
get(name)

if __name__ == '__main__':
for i in range(10):
p = Process(target=task,args=('路人%s'%i,))
p.start()

'''
<路人0>查看剩余票数[1]
<路人2>查看剩余票数[1]
<路人1>查看剩余票数[1]
<路人3>查看剩余票数[1]
<路人4>查看剩余票数[1]
<路人5>查看剩余票数[1]
<路人6>查看剩余票数[1]
<路人7>查看剩余票数[1]
<路人8>查看剩余票数[1]
<路人9>查看剩余票数[1]
<路人0 购票成功>
<路人2 购票成功>
<路人1 购票成功>
<路人3 购票成功>
<路人4 购票成功>
<路人5 购票成功>
<路人6 购票成功>
<路人7 购票成功>
<路人8 购票成功>
<路人9 购票成功>

并发的执行查看同一个文件,于是都看到了剩余1张票,最后都购票成功于是 打起来了。。。。
'''

加锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from multiprocessing import  Process,Lock
import json
import time

def search(name):
time.sleep(1) # 模拟网络延迟
dic = json.load(open('db.txt',encoding='utf-8'))
print('<%s>查看剩余票数[%s]'%(name,dic['count']))

def get(name):
time.sleep(1)
dic = json.load(open('db.txt', encoding='utf-8'))
if dic['count']>0:
dic['count']-=1
time.sleep(3)
json.dump(dic,open('db.txt','w',encoding='utf-8'))

print('<%s 购票成功>'%name)
def task(name,mutex):
mutex.acquire()
search(name)
get(name)
mutex.release()

if __name__ == '__main__':
mutex = Lock()
for i in range(10):
p = Process(target=task,args=('路人%s'%i,mutex))
p.start()
'''
<路人0>查看剩余票数[1]
<路人0 购票成功>
<路人2>查看剩余票数[0]
<路人1>查看剩余票数[0]
<路人3>查看剩余票数[0]
<路人4>查看剩余票数[0]
<路人5>查看剩余票数[0]
<路人6>查看剩余票数[0]
<路人7>查看剩余票数[0]
<路人8>查看剩余票数[0]
<路人9>查看剩余票数[0]
'''

上述有一个问题必须等第一个人购票了其他人才能查票

做如下修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def task(name,mutex):

search(name)

mutex.acquire()
get(name)
mutex.release()

'''
<路人0>查看剩余票数[1]
<路人1>查看剩余票数[1]
<路人2>查看剩余票数[1]
<路人3>查看剩余票数[1]
<路人4>查看剩余票数[1]
<路人5>查看剩余票数[1]
<路人6>查看剩余票数[1]
<路人7>查看剩余票数[1]
<路人8>查看剩余票数[1]
<路人9>查看剩余票数[1]
<路人0 购票成功>
'''

互斥锁和join的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from multiprocessing import  Process,Lock
import json
import time

def search(name):
time.sleep(1) # 模拟网络延迟
dic = json.load(open('db.txt',encoding='utf-8'))
print('<%s>查看剩余票数[%s]'%(name,dic['count']))

def get(name):
time.sleep(1)
dic = json.load(open('db.txt', encoding='utf-8'))
if dic['count']>0:
dic['count']-=1
time.sleep(3)
json.dump(dic,open('db.txt','w',encoding='utf-8'))
print('<%s 购票成功>'%name)
else:
print('<%s 购票失败>' % name)
def task(name):
search(name)
get(name)

if __name__ == '__main__':
for i in range(10):
p = Process(target=task,args=('路人%s'%i,))
p.start()
p.join()

'''
去掉锁后改用join虽然保证了串行,影响了整个的查询效率变慢了
<路人0>查看剩余票数[1]
<路人0 购票成功>
<路人1>查看剩余票数[0]
<路人1 购票失败>
<路人2>查看剩余票数[0]
<路人2 购票失败>
<路人3>查看剩余票数[0]
<路人3 购票失败>
<路人4>查看剩余票数[0]
<路人4 购票失败>
<路人5>查看剩余票数[0]
<路人5 购票失败>
<路人6>查看剩余票数[0]
<路人6 购票失败>
<路人7>查看剩余票数[0]
<路人7 购票失败>
<路人8>查看剩余票数[0]
<路人8 购票失败>
<路人9>查看剩余票数[0]
<路人9 购票失败>
'''