python线程锁怎么使用_Python程序中的线程操作-锁

一、同步锁

1.1 多个线程抢占资源的情况

from threading import Thread

import os,time

def work():

global n

temp=n

time.sleep(0.1)

n=temp-1

if __name__ == '__main__':

n=100

l=[]

for i in range(100):

p=Thread(target=work)

l.append(p)

p.start()

for p in l:

p.join()

print(n) #结果可能为99

1.1.1 对公共数据的操作

import threading

R=threading.Lock()

R.acquire()

'''

对公共数据的操作

'''

R.release()

1.2 同步锁的引用

from threading import Thread,Lock

import os,time

def work():

global n

lock.acquire()

temp=n

time.sleep(0.1)

n=temp-1

lock.release()

if __name__ == '__main__':

lock=Lock()

n=100

l=[]

for i in range(100):

p=Thread(target=work)

l.append(p)

p.start()

for p in l:

p.join()

print(n) #结果肯定为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全

1.3 互斥锁与join的区别

#不加锁:并发执行,速度快,数据不安全

from threading import current_thread,Thread,Lock

import os,time

def task():

global n

print('%s is running' %current_thread().getName())

temp=n

time.sleep(0.5)

n=temp-1

if __name__ == '__main__':

n=100

lock=Lock()

threads=[]

start_time=time.time()

for i in range(100):

t=Thread(target=task)

threads.append(t)

t.start()

for t in threads:

t.join()

stop_time=time.time()

print('主:%s n:%s' %(stop_time-start_time,n))

'''

Thread-1 is running

Thread-2 is running

......

Thread-100 is running

主:0.5216062068939209 n:99

'''

#不加锁:未加锁部分并发执行,加锁部分串行执行,速度慢,数据安全

from threading import current_thread,Thread,Lock

import os,time

def task():

#未加锁的代码并发运行

time.sleep(3)

print('%s start to run' %current_thread().getName())

global n

#加锁的代码串行运行

lock.acquire()

temp=n

time.sleep(0.5)

n=temp-1

lock.release()

if __name__ == '__main__':

n=100

lock=Lock()

threads=[]

start_time=time.time()

for i in range(100):

t=Thread(target=task)

threads.append(t)

t.start()

for t in threads:

t.join()

stop_time=time.time()

print('主:%s n:%s' %(stop_time-start_time,n))

'''

Thread-1 is running

Thread-2 is running

......

Thread-100 is running

主:53.294203758239746 n:0

'''

# 有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊

# 没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是

# start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的

# 单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高.

from threading import current_thread,Thread,Lock

import os,time

def task():

time.sleep(3)

print('%s start to run' %current_thread().getName())

global n

temp=n

time.sleep(0.5)

n=temp-1

if __name__ == '__main__':

n=100

lock=Lock()

start_time=time.time()

for i in range(100):

t=Thread(target=task)

t.start()

t.join()

stop_time=time.time()

print('主:%s n:%s' %(stop_time-start_time,n))

'''

Thread-1 start to run

Thread-2 start to run

......

Thread-100 start to run

主:350.6937336921692 n:0 #耗时是多么的恐怖

'''

)

二、死锁与递归锁

进程也有死锁与递归锁,在进程那里忘记说了,放到这里一起说了。

所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁

2.1 死锁

from threading import Lock as Lock

import time

mutexA=Lock()

mutexA.acquire()

mutexA.acquire()

print(123)

mutexA.release()

mutexA.release()

解决方法:递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁。

2.2 递归锁RLock

from threading import RLock as Lock

import time

mutexA=Lock()

mutexA.acquire()

mutexA.acquire()

print(123)

mutexA.release()

mutexA.release()

三、典型问题:科学家吃面

3.1 死锁问题

import time

from threading import Thread,Lock

noodle_lock = Lock()

fork_lock = Lock()

def eat1(name):

noodle_lock.acquire()

print('%s 抢到了面条'%name)

fork_lock.acquire()

print('%s 抢到了叉子'%name)

print('%s 吃面'%name)

fork_lock.release()

noodle_lock.release()

def eat2(name):

fork_lock.acquire()

print('%s 抢到了叉子' % name)

time.sleep(1)

noodle_lock.acquire()

print('%s 抢到了面条' % name)

print('%s 吃面' % name)

noodle_lock.release()

fork_lock.release()

for name in ['哪吒','nick','tank']:

t1 = Thread(target=eat1,args=(name,))

t2 = Thread(target=eat2,args=(name,))

t1.start()

t2.start()

3.2 递归锁解决死锁问题

import time

from threading import Thread,RLock

fork_lock = noodle_lock = RLock()

def eat1(name):

noodle_lock.acquire()

print('%s 抢到了面条'%name)

fork_lock.acquire()

print('%s 抢到了叉子'%name)

print('%s 吃面'%name)

fork_lock.release()

noodle_lock.release()

def eat2(name):

fork_lock.acquire()

print('%s 抢到了叉子' % name)

time.sleep(1)

noodle_lock.acquire()

print('%s 抢到了面条' % name)

print('%s 吃面' % name)

noodle_lock.release()

fork_lock.release()

for name in ['哪吒','nick','tank']:

t1 = Thread(target=eat1,args=(name,))

t2 = Thread(target=eat2,args=(name,))

t1.start()

t2.start()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值