- 本文将结合一个具体的例子来介绍如何使用线程锁的概念来实现当多线程访问同一个变量的情况,并简单的记录和实现了线程终止的方法。
- 任务描述
- 使用字典等哈希的方式来根据键查值 是一个很经典的问题。但是,如果在实际应用中字典,不可能一次加载完。这时候就需要将大词典切分成很多个小词典,然后每次加载一个词典进行查找。
- 如果使用多线程,就可以让每个线程查找某几个词典,从而实现并行查找。
- 但是这里边存在一个问题:那就是已经查找过的键就不需要再查找了,所以需要一个中间变量来存储已经查过的键
- 问题实例:本任务处理一个根据AUI查询其所对应的术语的问题。即给定一个AUI列表,以字典的形式返回每个AUI所对应的术语。
- 代码实现
- 定义基本变量,首先所有线程都需要访问的变量需要定义为全局变量
#带查找列表 AUI_list=["A0006504","A0026558","A0028920","A0037508","A0042049","A0048405"] #查找成功的key的列表 move_list = [] #定义一个全局变量,所有线程都可以操作 #定义一个锁 counter_lock = threading.Lock() #存储获取的结果 aui_term={}
- 重载run方法
global AUI_list,move_list,counter_lock,aui_term global thread_list #定义每个线程需要访问从起始变化开始的4个词典 for count in range(self.start_dicts,self.start_dicts+4): #获取待访问词典名 file_name="MRAUIST_"+str(count)+".json" dicts=fo.loadDict("./data/"+file_name) print(self.threadName,"打开了",file_name) #访问AUI元素 for item in AUI_list: if(item in dicts.keys()): #匹配成功 if counter_lock.acquire(): #设置锁,用于修改move_list aui_term[item]=dicts[item] print(self.threadName,item,dicts[item]) move_list.append(item) counter_lock.release() #释放锁
- 上述代码中,首先定义每个线程需要最多访问4个词典,所以从start_dicts开始,往后循环4次。并需要重新设置文件名
- 开启子线程
strid_list=[0,4,8,12,16,20] thread_list = [] def test(): for i in range(6): print("start",datetime.datetime.now()) t =MyThread(i,strid_list[i]) thread_list.append(t) t.start()
- 上述过程,定义了一个基本的基于多线程的多词典查找方法,但有时候,一个线程还没有访问完所有需要访问的词典时,所有的AUI可能都已经成功的查找,这是,就需要设置线程的停止。
- 定义基本变量,首先所有线程都需要访问的变量需要定义为全局变量
- 线程的终止
- 但是对于python来讲,线程只有start而没有end,因为一旦没有合理的关闭线程,就可能导致Bug。所以线程终止最重要的事情就是如何清理线程。
- 参考如何优雅地终止python线程,作者提出了三种线程终止的方法,本任务采取第二种方法,如果您对其他方法感兴趣,轻移步上述链接。
- 代码实现,定义基本的raise方法
def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1: # """if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect""" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") def stop_thread(thread): _async_raise(thread.ident, SystemExit)
- 设置子线程终止条件
if(len(AUI_list) == len(move_list)): print("终止线程", self.threadName,file_name) stop_thread(thread_list[self.arg])
- 主线程监听子线程结束,输出结果
while True: if(len(AUI_list) == len(move_list)): #监听子线程终止条件 print(aui_term) break
- 函数执行结果如下
start 2019-05-17 18:02:39.938454 start 2019-05-17 18:02:39.938454 start 2019-05-17 18:02:39.939454 thread_0 打开了 MRAUIST_0.json start 2019-05-17 18:02:39.941457 thread_1 打开了 MRAUIST_4.json thread_2 打开了 MRAUIST_8.json start 2019-05-17 18:02:39.943457 thread_0 打开了 MRAUIST_1.json thread_2 A0028920 Bacteroides corrodens thread_1 打开了 MRAUIST_5.json thread_3 打开了 MRAUIST_12.json thread_0 A0006504 Abdominal viscera start 2019-05-17 18:02:39.946459 thread_3 A0037508 Chemistry main thread end! thread_4 打开了 MRAUIST_16.json thread_5 打开了 MRAUIST_20.json thread_1 打开了 MRAUIST_6.json thread_0 打开了 MRAUIST_2.json thread_2 打开了 MRAUIST_9.json thread_3 打开了 MRAUIST_13.json thread_2 打开了 MRAUIST_10.json thread_3 打开了 MRAUIST_14.json thread_3 A0042049 Confidentiality thread_0 打开了 MRAUIST_3.json thread_4 打开了 MRAUIST_17.json thread_4 A0048405 Dicrocoelium dendriticum thread_2 打开了 MRAUIST_11.json thread_1 打开了 MRAUIST_7.json thread_1 A0026558 Arthritic Psoriasis 终止线程 thread_1 MRAUIST_7.json thread_5 打开了 MRAUIST_21.json {'A0028920': 'Bacteroides corrodens', 'A0006504': 'Abdominal viscera', 'A0037508': 'Chemistry', 'A0042049': 'Confidentiality', 'A0048405': 'Dicrocoelium dendriticum', 'A0026558': 'Arthritic Psoriasis'} 终止线程 thread_5 MRAUIST_21.json thread_3 打开了 MRAUIST_15.json 终止线程 thread_3 MRAUIST_15.json thread_4 打开了 MRAUIST_18.json 终止线程 thread_4 MRAUIST_18.json
- 上述结果中,线程0已经执行完毕,所以不会被终止,可以看到线程3打开了第15个词典,然后马上就终止了线程
- 参考
线程锁
最新推荐文章于 2024-08-08 08:56:22 发布