044.Python线程的数据安全

python

线程的数据安全

1 数据混乱现象

from threading import Thread,Lock

num = 0

lst = []

def func1():

global num

for i in range(100000):

num -= 1

def func2():

global num

for i in range(100000):

num += 1

for i in range (10):

# 启动线程1

t1 = Thread(target=func1)

t1.start()

# 启动线程2

t2 = Thread(target=func2)

t2.start()

lst.append(t1)

lst.append(t2)

for i in lst:

i.join()

print("主线程执行结束")

print(num)

执行

由于共享同一份,会出现数据混乱,如下结果

[root@node10 python]# python3 test.py

主线程执行结束

173624

[root@node10 python]# python3 test.py

主线程执行结束

131875

[root@node10 python]# python3 test.py

主线程执行结束

-4279

[root@node10 python]# python3 test.py

主线程执行结束

-93587

[root@node10 python]# python3 test.py

主线程执行结束

145643

这是因为线程是并发执行,同同一时间会有多个线程拿到同一个数据进行计算,然后再放回去,导致一个数字被多个线程修改,结果不准确

2 引入锁机制

from threading import Thread,Lock

num = 0

lst = []

def func1(lock):

global num

for i in range(100000):

#上锁修改数据

lock.acquire()

num -= 1

#解锁释放

lock.release()

def func2(lock):

global num

for i in range(100000):

#使用with,自动上锁和解锁

with lock:

num += 1

lock = Lock()

for i in range (10):

# 启动线程1

t1 = Thread(target=func1,args=(lock,))

t1.start()

# 启动线程2

t2 = Thread(target=func2,args=(lock,))

t2.start()

lst.append(t1)

lst.append(t2)

for i in lst:

i.join()

print("主线程执行结束")

print(num)

执行

[root@node10 python]# python3 test.py

主线程执行结束

0

结果正确,但是消耗的时间毕竟长,但是可以换取数据正确

3 信号量

import time,random,os

def func(i,sem):

time.sleep(random.uniform(0.1,1))

with sem:

print (i)

print (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

time.sleep(random.uniform(3,6))

sem = Semaphore(5)

for i in range (20):

Thread(target = func,args=(i,sem)).start()

执行

[root@node10 python]# python3 test.py

3

2020-02-23 03:55:24

5

2020-02-23 03:55:24

14

2020-02-23 03:55:24

18

2020-02-23 03:55:24

6

2020-02-23 03:55:24

0

2020-02-23 03:55:27

2

2020-02-23 03:55:29

15

2020-02-23 03:55:29

1

2020-02-23 03:55:29

19

2020-02-23 03:55:30

12

2020-02-23 03:55:32

4

2020-02-23 03:55:32

17

2020-02-23 03:55:34

16

2020-02-23 03:55:34

13

2020-02-23 03:55:35

7

2020-02-23 03:55:36

10

2020-02-23 03:55:36

8

2020-02-23 03:55:39

9

2020-02-23 03:55:39

11

2020-02-23 03:55:40

信号量就相当于同时可以上多把锁

死锁,递归锁,互斥锁

4 死锁现象

模拟一个俱乐部玩枪,两把枪,两盒子弹,四个人同时抢,只有同时抢到子弹和枪的人,才能玩枪

初步逻辑

from threading import Thread,Lock

import time

#首先创建两把锁

gun = Lock()

bullet = Lock()

#定义第一种,先抢到枪,再抢到子弹

def play1(name):

#抢到枪,上锁

gun.acquire()

print("%s拿到枪"%(name))

#抢到子弹上锁

bullet.acquire()

print ("%s抢到子弹"%(name))

print ("开枪玩一会")

time.sleep(0.5)

#放下枪,解锁

gun.release()

print("%s放下枪"%(name))

#放下子弹,解锁

bullet.release()

print("%s放下子弹"%(name))

#定义第二种,先抢到子弹,再抢到枪

def play2(name):

#抢到子弹上锁

bullet.acquire()

print ("%s抢到子弹"%(name))

#抢到枪,上锁

gun.acquire()

print("%s拿到枪"%(name))

print ("开枪玩一会")

time.sleep(0.5)

#放下子弹,解锁

bullet.release()

print("%s放下子弹"%(name))

#放下枪,解锁

gun.release()

print("%s放下枪"%(name))

name_lst1 = ["John","Jim"]

name_lst2 = ["Tom","Jerry"]

for name in name_lst1:

Thread(target=play1,args=(name,)).start()

for name in name_lst2:

Thread(target=play2,args=(name,)).start()

这种情况就会有死锁现象

多次执行,结果如下

[root@node10 python]# python3 test.py

John拿到枪

Tom抢到子弹

#阻塞,是因为John和Tom同时上了枪锁和子弹锁,但是都没有解锁,造成死锁

[root@node10 python]# python3 test.py

John拿到枪

John抢到子弹

开枪玩一会

John放下枪

John放下子弹

Jim拿到枪

Tom抢到子弹

#阻塞,这次是John顺利的玩一局,但是到Jim和Tom同时抢到枪和子弹,上锁,但是没有解锁,造成死锁

[root@node10 python]# python3 test.py

John拿到枪

John抢到子弹

开枪玩一会

John放下枪

John放下子弹

Tom抢到子弹

Jim拿到枪

#阻塞

5 递归锁介绍

上几把锁,解几把锁

from threading import Thread,RLock

rlock = RLock()

def func(name):

rlock.acquire()

print(name,1)

rlock.acquire()

print(name,2)

rlock.acquire()

print(name,3)

rlock.release()

rlock.release()

rlock.release()

for i in range(10):

t = Thread(target=func,args=("name%s" % (i),) )

t.start()

print("程序执行结束")

执行

[root@node10 python]# python3 ceshi.py

name0 1

name0 2

name0 3

name1 1

name1 2

name1 3

name2 1

name2 2

name2 3

name3 1

name3 2

name3 3

程序执行结束

name4 1

name4 2

name4 3

name5 1

name5 2

name5 3

name6 1

name6 2

name6 3

name7 1

name7 2

name7 3

name8 1

name8 2

name8 3

name9 1

name9 2

name9 3

6 利用递归锁,解决死锁现象

临时用于快速解决服务器崩溃死锁的问题,用递归锁应急问题

from threading import Thread,RLock

import time

#首先创建递归锁

gun=bullet = RLock()

#定义第一种,先抢到枪,再抢到子弹

def play1(name):

#抢到枪,上锁

gun.acquire()

print("%s拿到枪"%(name))

#抢到子弹上锁

bullet.acquire()

print ("%s抢到子弹"%(name))

print ("开枪玩一会")

time.sleep(0.5)

#放下枪,解锁

gun.release()

print("%s放下枪"%(name))

#放下子弹,解锁

bullet.release()

print("%s放下子弹"%(name))

#定义第二种,先抢到子弹,再抢到枪

def play2(name):

#抢到子弹上锁

bullet.acquire()

print ("%s抢到子弹"%(name))

#抢到枪,上锁

gun.acquire()

print("%s拿到枪"%(name))

print ("开枪玩一会")

time.sleep(0.5)

#放下子弹,解锁

bullet.release()

print("%s放下子弹"%(name))

#放下枪,解锁

gun.release()

print("%s放下枪"%(name))

name_lst1 = ["John","Jim"]

name_lst2 = ["Tom","Jerry"]

for name in name_lst1:

Thread(target=play1,args=(name,)).start()

for name in name_lst2:

Thread(target=play2,args=(name,)).start()

执行

[root@node10 python]# python3 test.py

John拿到枪

John抢到子弹

开枪玩一会

John放下枪

John放下子弹

Jim拿到枪

Jim抢到子弹

开枪玩一会

Jim放下枪

Jim放下子弹

Tom抢到子弹

Tom拿到枪

开枪玩一会

Tom放下子弹

Tom放下枪

Jerry抢到子弹

Jerry拿到枪

开枪玩一会

Jerry放下子弹

Jerry放下枪

执行成功,神奇

7 使用互斥锁解决

从语法上来看,锁是可以互相嵌套的,但是不要使用

上一次锁,就对应解开一把锁,形成互斥锁

拿枪和拿子弹是同时的,上一把锁就够了,不要分开上锁,也不要去写锁的嵌套,容易死锁

from threading import Thread,Lock

import time

#首先创建递归锁

mylock = Lock()

#定义第一种,先抢到枪,再抢到子弹

def play1(name):

#抢到枪和子弹,上锁

mylock.acquire()

print("%s拿到枪"%(name))

print ("%s抢到子弹"%(name))

print ("开枪玩一会")

time.sleep(0.5)

#放下枪,和子弹解锁

print("%s放下枪"%(name))

print("%s放下子弹"%(name))

mylock.release()

#定义第二种,先抢到子弹,再抢到枪

def play2(name):

#抢到枪子弹上锁

mylock.acquire()

print ("%s抢到子弹"%(name))

print("%s拿到枪"%(name))

print ("%s开枪玩一会"%(name))

time.sleep(0.5)

#放枪下子弹,解锁

print("%s放下子弹"%(name))

print("%s放下枪"%(name))

mylock.release()

name_lst1 = ["John","Jim"]

name_lst2 = ["Tom","Jerry"]

for name in name_lst1:

Thread(target=play1,args=(name,)).start()

for name in name_lst2:

Thread(target=play2,args=(name,)).start()

执行

[root@node10 python]# python3 test.py

John拿到枪

John抢到子弹

开枪玩一会

John放下枪

John放下子弹

Jim拿到枪

Jim抢到子弹

开枪玩一会

Jim放下枪

Jim放下子弹

Tom抢到子弹

Tom拿到枪

Tom开枪玩一会

Tom放下子弹

Tom放下枪

Jerry抢到子弹

Jerry拿到枪

Jerry开枪玩一会

Jerry放下子弹

Jerry放下枪

完成

以上是 044.Python线程的数据安全 的全部内容, 来源链接: utcz.com/z/386882.html

回到顶部