有趣的多线程 - Python
一般在多线程应用的时候,总有一些函数(或者代码)不愿意也(不应该)被多个线程同事执行,通常包括修改数据库、更新文件或者其他会产生竞态条件的类似情况。这时候就需要进行同步了。Python中用到的同步就是锁和信号量。
首先是示例锁,创建随机的线程并休眠随机秒。
1 """ 2 创建随机线程并休眠随机秒 3 """ 4 from threading import Thread, Lock, current_thread 5 from random import randrange 6 import time 7 from atexit import register 8 9 class cleanOutputSet(set): 10 # 一个集合(set)的子类,只实现一个方法 11 def __str__(self): 12 return ','.join(x for x in self) 13 14 # 随机线程和随机休眠的生成器 15 randomSleepAndThread = (randrange(2, 5) for x in range(randrange(3, 7))) # 随机休眠2-4秒,线程的随机量为3-6 16 17 # 实例化cleanOutputSet 18 remainingThreads = cleanOutputSet() 19 20 # 线程锁 21 threadLock = Lock() 22 23 # 线程函数 24 def threadLoop(nsec): 25 # 首先获取当前线程的线程名 26 currentThreadName = current_thread().name 27 28 # 因为有加入到线程集合的操作,上锁 29 threadLock.acquire() 30 # 在这一对锁之间,需要将启动后的线程加入到线程集合 31 print(f'--线程 {currentThreadName} 启动于:{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))}') 32 # 启动后加入到线程集合 33 remainingThreads.add(currentThreadName) 34 threadLock.release() 35 # 释放锁后调用休眠 36 time.sleep(nsec) # 随机休眠 37 38 # 第二组锁产生在从集合序列中删除线程名的时候 39 threadLock.acquire() 40 print(f'--线程 {currentThreadName} 结束于:{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))}') 41 # 结束后删除 42 remainingThreads.remove(currentThreadName) 43 # 再查看剩下的线程 44 print('*********剩下的线程有:【{}】。*********'.format(remainingThreads or "None")) 45 threadLock.release() 46 47 def _main(): 48 # 主函数,用_表示只能从当前文件访问这个函数 49 for pause in list(randomSleepAndThread): 50 # 启动线程 51 Thread(target=threadLoop, args=(pause, )).start() 52 53 # 注册一个退出函数 54 @register 55 def _atexit(): 56 print('所有线程在:{} 完成'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))) 57 58 59 # 调用主函数 60 if __name__ == "__main__": 61 _main()
输出如下:
这种情况下在更新集合序列和从集合序列删除的时候,需要用到线程锁同步,如果没有线程同步锁,那输出可能是不可预料的,因为同一时间多个线程会抢夺添加到集合序列和从集合序列删除两种情况。