您的位置:首页 > 编程语言 > Python开发

关于Python的进程线程协程之thread模块

2017-04-25 18:13 796 查看

简介

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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息