简介
thread模块为python下的多线程处理,提供了产生线程的基本方法和锁方法的,支持建议不要和threading模块同时使用。
关于线程锁
所谓的锁,即基本的同步数据锁对象lock object,也称原语锁,简单锁,互斥锁,二值信号量,作用是同步数据,防止产生脏数据
thread模块方法和锁对象的描述
- start_new_thread(function,args,kwargs=None) 产生一个新线程对象,在新线程中调用指定参数(args和可选的kwargs)的函数function
- allocte_lock() 分配一个LockType类型的锁对象
- exit() 让线程退出
- LockType类型锁对象方法
- acquire(wait=None) 尝试获取锁对象
- locked() 线程对象如果获取了锁对象返回True,否则返回False
- release() 释放锁
实例一:
未使用thread模块的实例
解释器将变量以及函数读入内存之后,执行main函数,方法依次调用,顺序执行
from time import sleep,ctime
"""
the process that no mode of thread
"""
def loop0():
'''function for sleep 4s '''
print "start loop0 at: ",ctime()
sleep(4)
print "end loop0 at: ",ctime()
def loop1():
'''function for sleep 2s '''
print "start loop1 at: ", ctime()
sleep(2)
print "end loop1 at: ", ctime()
def main():
'''function of main'''
print "process start at: ".upper(),ctime()
loop0()
loop1()
print "process end at: ".upper(),ctime()
if __name__ == '__main__':
main()
执行结果如下:
PROCESS START AT: Tue Apr 25 16:48:04 2017
start loop0 at: Tue Apr 25 16:48:04 2017
end loop0 at: Tue Apr 25 16:48:08 2017
start loop1 at: Tue Apr 25 16:48:08 2017
end loop1 at: Tue Apr 25 16:48:10 2017
PROCESS END AT: Tue Apr 25 16:48:10 2017
实例二:
使用thread模块的实例
#_*_utf-8_*_
import thread
from time import sleep,ctime
"""
the process that have mode of thread
"""
def loop0():
'''A function for sleep 4s '''
print "start loop0 at: ",ctime()
sleep(4)
print "end loop0 at: ",ctime()
def loop1():
'''A function for sleep 2s '''
print "start loop1 at: ", ctime()
sleep(2)
print "end loop1 at: ", ctime()
def main():
'''A function of main'''
print "process start at: ".upper(),ctime()
thread.start_new_thread(loop0,())
thread.start_new_thread(loop1,())
sleep(6)
print "process end at: ".upper(),ctime()
if __name__ == '__main__':
main()
执行结果如下:
PROCESS START AT: Tue Apr 25 16:50:38 2017
start loop0 at: Tue Apr 25 16:50:38 2017
start loop1 at: Tue Apr 25 16:50:38 2017
end loop1 at: Tue Apr 25 16:50:40 2017
end loop0 at: Tue Apr 25 16:50:42 2017
PROCESS END AT: Tue Apr 25 16:50:44 2017
ps:如果在main函数里去掉sleep(6),那么,在主线程里将运行函数loop1和loop2的两个线程产生后,主线程将继续运行,不管产生的两个新线程是否执行完成,但此时系统一定会报错,如下:
PROCESS START AT: Tue Apr 25 16:56:36 2017
PROCESS END AT: Tue Apr 25 16:56:36 2017
Unhandled exception in thread started by
sys.excepthook is missing
lost sys.stderr
Unhandled exception in thread started by
sys.excepthook is missing
lost sys.stderr
为了避免以上情况(即当主线程退出时,所有的子线程不论是否还在工作,都会被强行退出)的出现,由此引入了守护线程,比thread更高级的threading模块支持守护线程,不过我们可以用后文讲到的锁机制来模拟守护线程的作用作为弥补
线程锁:thread模块的锁方法
针对python的GIL,python的多线程处理在cpu性能欠佳的情况下往往会产生脏数据,比如多个线程在同时修改共享数据,例如全局变量,此时可能会产生数据不同步,因为python2.7内部默认每一个线程执行100条cpu指令(差不多这么多条),执行完了我切换到另一个线程执行100条指令,假设在某个场景下,主线程产生两个线程A,B,同时修改全局变量i=0,让它增一,A线程刚拿到i的初始值准备修改,而并未开始修改,此时cpu的100条指令执行完,此时保存现场,切换到B线程执行,它获取到i的初始值依旧未变,即跟A拿到的一样,那么,照这样执行下去,最后A,B修改后返回的i的值就会是相同的即i=1,此时,就产生了数据不同步,脏数据产生。这也是锁出现的原因。
实例三:
thread模块:未设置锁的多线程实例
#_*_utf-8_*_
import thread
"""
the process that have mode of thread and no Lock
"""
count = 0
def loop(arg):
'''function for modify the global value
count and sleep 2s
'''
global count
count += 1
sleep(1)
print "count of modified in loop %s is :"%arg,count
def main():
'''function of main'''
print "begin count = ".upper,count
for i in range(50):
thread.start_new_thread(loop,(i,))
sleep(10)
print "final count = ".upper,count
if __name__ == '__main__':
main()
运行结果如下:
<built-in method upper of str object at 0x00000000034DD870> 0
count of modified in loop 0 is : count of modified in loop 2 is :1
2count of modified in loop 1 is :
count of modified in loop 3 is :3
4count of modified in loop 4 is :
count of modified in loop 6 is :6count of modified in loop 5 is :
7count of modified in loop 8 is :7
8
count of modified in loop 7 is :count of modified in loop 9 is : <built-in method upper of str object at 0x00000000034EF300> 10 10
10
······此处省略n行······
count of modified in loop 44 is :count of modified in loop 41 is :41
Process finished with exit code 0
ps:*脏数据的产生*:由于产生的线程未设置互斥锁,导致全局变量count最终修改结果产生误差,并且所有的线程在输出的时候都在抢占输出中断导致输出乱序
实例四:
thread模块:设置锁的多线程实例
#_*_utf-8_*_
import thread
"""
the process that have mode of thread and Lock
"""
count = 0
#global value
num = 50
#number of threads
Lock_Pool = []
#object of locks
def loop(arg,Lp):
'''function for modify the global value
count
'''
global count
count += 1
print "count of modified in loop %s is :"%arg,count
Lp.release()
def Thread_End(arg):
for i in range(arg):
while Lock_Pool[i].locked :pass
def LockPool():
'''A function that produce intantiation of Lock
'''
for i in range(num):
lock = thread.allocate()
lock.acquire()
Lock_Pool.append(lock)
def main():
'''A function of main:
produce Lock pool
start every thread
wait every thread finish in main until the all end
'''
LockPool()
#produce Locks
print "begin count = ".upper,count
for i in range(num):
thread.start_new_thread(loop,(i,Lock_Pool[i]))
Thread_End(num)
#wait all threads end
print "final count = ".upper,count
if __name__ == '__main__':
main()
其中的Thread_End函数就是本文实例二提到的模拟守护线程的功能,通过判断每个线程的锁是否还在获取状态来阻塞主线程,用这样的低级的一个一个判断的方法来弥补thread模块不支持守护线程的缺陷
def Thread_End(arg):
for i in range(arg):
while Lock_Pool[i].locked :pass
关于线程同步:其中函数LockPool的定义是为了,实现线程们的同步执行,避免有的线程还在获取锁,有的线程已经运行结束了
def LockPool():
'''A function that produce intantiation of Lock
'''
for i in range(num):
lock = thread.allocate()
lock.acquire()
Lock_Pool.append(lock)