线程锁(互斥锁Mutex)
一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据,这样就可能使结果不正确,每次运行的结果不同,为了避免自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据,这里的锁称为线程锁。
在python2.几的版本上会有多线程同时修改同一数据,结果不同的情况,在python3上不会出现这种情况。
没加锁的效果:加大线程多试几遍 。
#conding:UTF-8
import threading,time
num=0
def run(m): #子线程
global num
print'take',m
time.sleep(2) #方法中的时间间隔在显示结果时间上不显现,因为t1.start()是并发执行的。
print'run结束',m
num+=1 #多线程同时操作
app=[]
start_time=time.time()
for i in range(10): #主线程
t1=threading.Thread(target=run,args=('t-%s'%i,))
t1.start() #循环中的对象并发执行调用run函数。把time.sleep(2)放到t1.start()的上面时间间隔就会显现。
app.append(t1)
for t in app:
t.join() #等待线程结束
print 'cost:',time.time()-start_time
print num #得出num的值
python2添加锁,加锁后线程就会形成串行。
#conding:UTF-8
import threading,time
num=0
def run(m): #子线程
sock.acquire() #解锁
global num
print'take',m
time.sleep(2) #方法中的时间间隔在显示结果时间上不显现,因为t1.start()是并发执行的。
print'run结束',m
num+=1
sock.release()#释放锁
sock=threading.Lock()
app=[]
start_time=time.time()
for i in range(10): #主线程
t1=threading.Thread(target=run,args=('t-%s'%i,))
t1.start() #循环中的对象并发执行调用run函数。把time.sleep(2)放到t1.start()的上面时间间隔就会显现。
app.append(t1)
for t in app:
t.join() #等待线程结束
print 'cost:',time.time()-start_time
print num
结果形成串行:
take t-0
run结束 t-0
take t-1
run结束 t-1
take t-2
run结�� t-2
take t-3
run结束 t-3
take t-4
run结�� t-4
take t-5
run结�� t-5
take t-6
run结束 t-6
take t-7
run结�� t-7
take t-8
run结�� t-8
take t-9
run结束 t-9
cost: 20.007999897
10
递归锁(互斥锁)
在一个大锁中还要再包含子锁
#conding:UTF-8
import threading,time
def run1():
print("grab the first part data")
lock.acquire()
global num
num +=1
lock.release()
return num
def run2():
print("grab the second part data")
lock.acquire()
global num2
num2+=1
lock.release()
return num2
def run3():
lock.acquire()
res = run1()
print('--------between run1 and run2-----')
res2 = run2()
lock.release()
print(res,res2)
if __name__ == '__main__':
num,num2 = 0,0
lock = threading.RLock() #递归锁 这里如果不带R的话,将会出现找不到锁,死循环的情况。
for i in range(10):
t = threading.Thread(target=run3)
t.start()
while threading.active_count() != 1:
print(threading.active_count())
print(num,num2)
else:
print('----all threads done---')
print(num,num2)
信号量
互斥锁 同时只允许一个线程更改数据,而信号量是同时允许一定数量的线程更改数据。
#conding:UTF-8
import threading,time
def run(n):
semaphore.acquire() #信号获取
time.sleep(2)
print("run the thread: %s\n" %n)
semaphore.release() #信号释放
if __name__ == '__main__':
semaphore = threading.BoundedSemaphore(5) #定义信号量对象,最多允许5个线程同时运行
for i in range(20):
t = threading.Thread(target=run,args=(i,))
t.start()
while threading.active_count() != 1:
pass #print threading.active_count()
else:
print('----all threads done---')
Events(事件)
通过Event来实现两个或多个线程间的交互。
event=threading.Event() #定义事件对象
event.wait() # Event对象wait的方法只有在内部信号为真的时候才会很快的执行并完成返回。当Event对象的内部信号标志位假时,则wait方法一直等待到其为真时才返回。
event.set() # 使用Event的set()方法可以设置Event对象内部的信号标志为真。Event对象提供了isSet()方法来判断其内部信号标志的状态,当使用event对象的set()方法后,isSet()方法返回真.
event.clear() # 使用Event对象的clear()方法可以清除Event对象内部的信号标志,即将其设为假,当使用Event的clear方法后,isSet()方法返回假
以下游戏规则:
红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。
#conding:UTF-8
import time
import threading
count=0
event=threading.Event() #创建Event对象
event.set() #设置标志位
def lingter():
global count
while True:
if count<5:#5秒内绿灯亮
print 'greed lignt is on....'
elif count>=5and count<10:#之外红灯亮
event.clear() #清空标志位
print 'red lignt is wait....'
else:
count=0
event.set()
count+=1
time.sleep(1)
def car(name):
while True:
if event.is_set(): #判断标志状态
print '%s is running...'%name
else:
print '%s is waitting...'%name
event.wait()
print '%s is going run...'%name
time.sleep(1)
lingt=threading.Thread(target=lingter,)
lingt.start()
car1=threading.Thread(target=car,args=('car1',))
car1.start()