python 线程之_thread
_thread module:
基本用法:
1 def child(tid): 2 print("hello from child",tid) 3 _thread.start_new_thread(child,(1,)
1 使用_thread.start_new_thread() 方法来开始一个新的线程。这个调用接收一个函数对象(或其他可调用对象)和一个参数元组。这非常类似与python的function(*args)调用语法
类似的也可以接受一个关键字参数字典。
2 从操作的角度来说_thread.start_new_thread()的调用本身返回一个没有用的值。在函数调用结束后退住,如果在函数的调用过程中发生了异常会打印堆栈跟踪记录其他部分继续运 行。
3. 使用_thread启动线程的其他方法:
1 import _thread 2 3 def action(i): 4 print(i ** 32) 5 6 class Power: 7 def __init__(self,i): 8 self.i = i 9 def action(self): 10 print(self.i ** 32) 11 12 _thread.start_new_thread(action,(2,)) 13 14 _thread.start_new_thread(lambda:action(2), ()) 15 16 obj = Power() 17 _thread.start_new_thread(obj.action,())
运行多个线程及同步访问共享对象:
在多个线程运行的过程中,如果涉及到一个线程访问修改了一个全局作用域变量,那么这个改变对于此进程中的其他线程是可见的。
好处:使程序的线程间传递信息很简单,所谓的自带任务间通信机制。
坏处:需要注意数个线程同时改变全局对象和名称。如果有两个线程一起改变某个共享的对象,那么可能丢失一个或者共享对象的状态被损坏。
使用锁的概念可以确保在任何一个时间点只有一个线程持有锁。如果在持有期间其他线程请求获得锁,那么这个请求会被一直阻塞,直到释放此锁。
1. 使用_thread.allocate_lock创建一个锁对象可又多个线程轮流获取和释放
1 import _thread 2 import time 3 4 def counter(threadid, count): 5 for i in range(count): 6 time.sleep(1) 7 mutex.acquire() 8 print('thread id [{0}] => {1}'.format(threadid, i)) 9 mutex.release() 10 for i in range(5): 11 _thread.start_new_thread(counter, (i, 5)) 12 13 mutex = _thread.allocate_lock() 14 15 time.sleep(7) 16 print('main process exit')
2. 在上面的代码中,主线程为了等待所有的子线程完成后在退出使用time.sleep(7)这样的方式,可以使用等待线程退出的其他方式来更灵活的等待。
1. 针对每一个线程创建相应的锁对象,形成锁列表,在线程函数运行之后,获取这个锁对象,在主线程对这个列表进行循环判断。如果所有的锁都是获取状态那么主线程可以退出,反之需要等待所有线程完成之后退出。
1 import _thread 2 import time 3 4 count = 5 5 mutex = _thread.allocate_lock() 6 exitmutexs = [_thread.allocate_lock() for i in range(count)] 7 8 def child(threadid,count): 9 for i in range(count): 10 time.sleep(1) 11 mutex.acquire() 12 print('[{0}] => {1}'.format(threadid, i)) 13 mutex.release() 14 exitmutexs[threadid].acquire() 15 16 for i in range(count): 17 _thread.start_new_thread(child, (i, 5)) 18 19 for m in exitmutexs: 20 while not m.locked(): pass 21 22 print('main thread exiting')
2. 上面的代码有点大财效用,通过检查锁的locked方法来查看状态。但是主线程仅仅关注所有的锁被获取,其实可以简单使用包含列表而非锁的方式来达到相同的效果
1 import _thread 2 import time 3 4 threadNum = 5 5 mutex = _thread.allocate_lock() 6 #使用bool的标识列表来判断 7 exitmutexex = [False] * threadNum 8 9 10 def counter(threadid, count): 11 for i in range(count): 12 time.sleep(1) 13 mutex.acquire() 14 print('[{0}] => {1}'.format(threadid, i)) 15 mutex.release() 16 exitmutexex[threadid] = True #向主线程发出信号 17 18 for i in range(threadNum): 19 _thread.start_new_thread(counter, (i, 5)) 20 21 while False in exitmutexex:pass #判断所有线程是否完成 22 print('main process existing')
3. 在上面的两个脚本存在的问题,I 主线程在繁忙等待中切换,这样在紧凑的程序可能导致显著的性能下降。这个可以使用time.sleep()替换pass
II 使用with语句可以获取锁然后在执行完成之后自动释放锁。
1 import _thread 2 import time 3 4 threadNum = 5 5 mutex = _thread.allocate_lock() 6 exitmutexes = [_thread.allocate_lock() for i in range(5)] 7 8 9 def counter(threadid, count): 10 for i in range(count): 11 time.sleep(1) 12 with mutex: 13 print('[{0}] => {1}'.format(threadid, i)) 14 exitmutexes[threadid].acquire() 15 16 for i in range(threadNum): 17 _thread.start_new_thread(counter,(i, 5)) 18 19 while not all(m.locked() for m in exitmutexes): time.sleep(0.25) 20 print('main process existing')