常用方法
threading.Lock()
返回一个lock对象,当多个线程对同一数据同时进行修改时,则可能出现结果的不确定性,为了保证数据的结果在我们预期内,则,需要对线程进行同步。
lock对象则为我们提供acquire()和release()两个方法,对于那些在同一时间内只允许一个线程进行操作修改的数据,可将其放在这两个方法之间。
代码(没有对数据加锁):
import threading
num=0
lock=threading.Lock()
def change(n):
global num #对数据先加后减
num=num+n
num=num-n
def run(n):
for i in range(10000000):
change(n)
if __name__=="__main__":
t1=threading.Thread(target=run,args=(5,))
t2=threading.Thread(target=run,args=(10,))
t1.start()
t2.start()
t1.join()
t2.join()
print(num) #理论上结果为0
结果:
195
155
135
代码(对数据加锁):
import threading
num=0
lock=threading.Lock()
def change(n):
global num
num=num+n
num=num-n
def run(n):
for i in range(10000000):
lock.acquire()
change(n)
lock.release()
if __name__=="__main__":
t1=threading.Thread(target=run,args=(5,))
t2=threading.Thread(target=run,args=(10,))
t1.start()
t2.start()
t1.join()
t2.join()
print(num)
结果:
0
0
0
threading.RLock()
与Lock对象的区别,在同一线程可多次调用RLock.acquire()方法,但acquire()必须与release()方法成对出现,否则就无法释放资源。
代码:
import threading
lock=threading.Lock()
rlock=threading.RLock()
if __name__=="__main__":
lock.acquire()
#lock.acquire() ##对同一线程使用lock.acquire()方法会产生死锁
lock.release()
#lock.release()
rlock.acquire()
rlock.acquire()
rlock.release()
rlock.release()
threading.Condition()
Condition对象相可以理解为一把高级锁,它在内部维护了一个锁对象(默认为RLock),同样提供了acquire()和release()方法,其实就是简单调用内部锁对象的方法。Condition还提供了wait(), notify()和notifyAll()方法(注意:必须在占用锁(acquire)后才能调用这些方法,否则会报RuntimeError异常)
Condition.wait([timeout])
线程挂起,直到收到notify()通知或是等等timeout秒后才会被唤醒运行。
Condition.notify(n=1)
通知其他等待的线程,当其它被挂起的线程受到notify通知,则会被唤醒。默认是通知一个线程,最多可通知n个线程。
Condition.notifyAll()
通知所有在等待的线程
代码:
import threading,time
def dask_1(cond):
cond.acquire()
print("开始任务一")
print("开始执行任务一第一阶段....")
time.sleep(3)
print("任务一第一阶段执行完成")
cond.wait(10)#任务一第一阶段执行完成后必须等待任务二第一阶段执行完才能继续执行任务一的第二阶段
print("开始执行任务一第二阶段....")
time.sleep(3)
print("任务一第二阶段执行完成")
cond.notify()#通知任务一第二阶段执行完成
cond.wait(10)
print("任务一执行完成")
cond.release()
def dask_2(cond):
cond.acquire()
print("开始任务二")
print("开始执行任务二第一阶段....")
time.sleep(5)
print("任务二第一阶段执行完成")
cond.notify()#任务二第一阶段执行完成通知任务一
cond.wait(10)#等待任务一执行完第二阶段,继而执行任务二第二阶段
print("开始执行任务二第二阶段....")
time.sleep(5)
print("任务二第二阶段执行完成")
cond.notify()
print("任务二执行完成")
cond.release()
if __name__=="__main__":
cond=threading.Condition()
task1=threading.Thread(target=dask_1,args=(cond,))
task2=threading.Thread(target=dask_2,args=(cond,))
task1.start()
task2.start()
结果:
开始任务一
开始执行任务一第一阶段....
任务一第一阶段执行完成
开始任务二
开始执行任务二第一阶段....
任务二第一阶段执行完成
开始执行任务一第二阶段....
任务一第二阶段执行完成
开始执行任务二第二阶段....
任务二第二阶段执行完成
任务二执行完成
任务一执行完成
threading.Semaphore(value=1)
Semaphore在内部管理着一个计数器。当调用acquire()方法时计数器减一,调用relsese()方法时计数器加一,计数器的值永远不可能小于0,当等于0时,调用acquire()方法时会阻塞。
Semaphore.acquire(blocking=True,timeout=None)
当blocking设置为False时,不会发生阻塞。
代码:
import threading,time
def run(semaphore,name):
#获得信号量,信号量减一
semaphore.acquire()
print("Thread name:%s"%name)
time.sleep(3)
#释放信号量,信号量加一
semaphore.release()
if __name__=="__main__":
#只允许4个线程同时运行
semaphore=threading.Semaphore(4)
for each in range(8):
t=threading.Thread(target=run,args=(semaphore, each))
t.start()
结果:
Thread name:0
Thread name:1
Thread name:2
Thread name:3
Thread name:4
Thread name:5
Thread name:6
Thread name:7
线程3以后的线程是在3秒后才打印出来的。
threading.BoundedSemaphore(value=1)
与Semaphore的区别,内部会对计数器进行检测,当计数量大于初始值时,抛出ValueError错误
代码:
import threading,time
def run(semaphore,name):
#获得信号量,信号量减一
semaphore.acquire(blocking=False)
print("Thread name:%s"%name)
time.sleep(3)
#释放信号量,信号量加一
semaphore.release()
if __name__=="__main__":
#只允许4个线程同时运行
semaphore=threading.BoundedSemaphore(4)
for each in range(8):
t=threading.Thread(target=run,args=(semaphore, each))
t.start()
结果:
Thread name:0
Thread name:1
Thread name:2
Thread name:3
Thread name:4
Thread name:5
Thread name:6
Thread name:7
ValueError: Semaphore released too many times
threading.Event()
事件处理机制:全局定义了一个Flag,初始值为False,当Flag为False时,线程掉用Event.wait时就会发生阻塞,而当Flag设置为True时,线程调用Event.wait()时不会发生阻塞,且当前所有等待的线程也会恢复运行。
该类提供了set()方法,将Flag设置为True,提供了clear()方法,将Flag设置为False,还有isSet()方法,检测Flag是否为True。
代码:
import threading,time
def run(event,name):
print("Thread of %s is wating..."%name)
event.wait()
print("Thread of %s is finished..."%name)
if __name__=="__main__":
#Flag初始值是Fales
event=threading.Event()
for each in range(10):
t=threading.Thread(target=run,args=(event,each))
t.start()
time.sleep(4)
if not event.isSet():
event.set()
结果:
Thread of 0 is wating...
Thread of 1 is wating...
Thread of 2 is wating...
Thread of 3 is wating...
Thread of 4 is wating...
Thread of 5 is wating...
Thread of 6 is wating...
Thread of 7 is wating...
Thread of 8 is wating...
Thread of 9 is wating...
Thread of 3 is finished...
Thread of 7 is finished...
Thread of 4 is finished...
Thread of 1 is finished...
Thread of 5 is finished...
Thread of 0 is finished...
Thread of 6 is finished...
Thread of 8 is finished...
Thread of 9 is finished...
Thread of 2 is finished...
代码是在4秒后运行结束
theading.active_count()
返回当前存活的线程数量。
代码:
import threading,time
def run():
#threading.current_thread():返回当前线程对象
thread=threading.current_thread()
print("Thread name is %s"% thread.getName())
time.sleep(10)
if __name__=="__main__":
for each in range(10):
t=threading.Thread(target=run)
t.start()
print("The number of current thread is %s"% threading.active_count())
代码:
Thread name is Thread-1
The number of current thread is 2
Thread name is Thread-2
The number of current thread is 3
Thread name is Thread-3
The number of current thread is 4
Thread name is Thread-4
The number of current thread is 5
Thread name is Thread-5
The number of current thread is 6
Thread name is Thread-6
The number of current thread is 7
Thread name is Thread-7
The number of current thread is 8
Thread name is Thread-8
The number of current thread is 9
Thread name is Thread-9
The number of current thread is 10
Thread name is Thread-10
The number of current thread is 11
还有以下方法,不一一举例
threading.current_thread()
返回当前线程对象。
threading.main_thread()
返回主线程对象。
threading.enumerate()
返回当前存活线程列表。
threading.get_ident()
返回当前线程pid。