1 import threading 2 import math 3 import datetime 4 5 # 多线程本质上是在一个 Python 程序里做的一个资源再分配,把几段代码的运行顺序进行先后调整达到 CPU 资源利用的最大化。 6 # 但是这么做的一个缺点就是资源竞争Resource Contention,意思就是有可能几段代码同时在读写一个参数的时候,把这个参数的数值搞混。 7 # 所以在多线程共享资源的情况下,需要在共享资源外部添加锁 Lock。 8 9 # 直接继承线程类,然后覆盖继承类函数的方法 10 class ThreadChild(threading.Thread): 11 # 初始化 init: 通常继承线程类会扩写父类的初始化,来传递参数等。 12 def __init__(self, num_list, name, ret_dic, ret_lock): 13 # 扩写父类的初始化,首先调用父类的初始化 14 threading.Thread.__init__(self) 15 self.num_list = num_list 16 self.name = name 17 self.ret_dic = ret_dic 18 self.ret_lock = ret_lock 19 return 20 21 # 运行 run: 这是一个必须要覆盖的函数。启动线程调用的 start() 函数就是运行这个函数,这里是需要运行的核心代码。 22 def run(self):# 覆盖重写函数 run 23 result = 0 24 for num in self.num_list: 25 result += math.sqrt(num * math.tanh(num) / math.log2(num) / math.log10(num)) 26 self.ret_lock.acquire()# 锁住, 锁住之后的代码将只能被一个线程执行下去,直到开锁 27 self.ret_dic[self.name] = result 28 self.ret_lock.release()# 开锁, 开锁之后,被锁住的资源和代码行又可以重新被其他线程读写 29 return 30 31 32 if __name__ == '__main__': 33 34 thread_pool = [] 35 ret_dic = {} 36 # 锁类 Lock: 在线程中需要读写一个共享资源的时候,通过锁类来锁住资源,防止另外的线程读写修改。 37 ret_lock = threading.Lock() 38 39 # 多线程 40 th_1 = ThreadChild(num_list=list(range(10, 3000000)), name='th_1', ret_dic=ret_dic, ret_lock=ret_lock) 41 th_2 = ThreadChild(num_list=list(range(3000000, 6000000)), name='th_2', ret_dic=ret_dic, ret_lock=ret_lock) 42 th_3 = ThreadChild(num_list=list(range(6000000, 9000000)), name='th_3', ret_dic=ret_dic, ret_lock=ret_lock) 43 thread_pool.append(th_1) 44 thread_pool.append(th_2) 45 thread_pool.append(th_3) 46 47 start_t = datetime.datetime.now() 48 49 # 非阻塞 start() 50 for th in thread_pool: 51 th.start() 52 53 # 阻塞 join() 54 for th in thread_pool: 55 th.join() 56 57 final_result = sum(ret_dic.values()) 58 end_t = datetime.datetime.now() 59 elapsed_sec = (end_t - start_t).total_seconds() 60 print("多线程计算结果: " + "{:.1f}".format(final_result) + ", 共消耗: " + "{:.2f}".format(elapsed_sec) + " 秒") 61 62 # 单线程 63 ret_dic.clear() 64 th_4 = ThreadChild(num_list=list(range(10, 9000000)), name='th_4', ret_dic=ret_dic, ret_lock=ret_lock) 65 start_t = datetime.datetime.now() 66 th_4.start()# 非阻塞 start() 67 th_4.join()# 阻塞 join() 68 final_result = sum(ret_dic.values()) 69 end_t = datetime.datetime.now() 70 elapsed_sec = (end_t - start_t).total_seconds() 71 print("单线程计算结果: " + "{:.1f}".format(final_result) + ", 共消耗: " + "{:.2f}".format(elapsed_sec) + " 秒") 72 73 # 多线程计算结果: 1484922580.2, 共消耗: 8.72 秒 74 # 单线程计算结果: 1484922580.2, 共消耗: 4.03 秒 75 76 # 把这两行注释掉 77 # th_3 = ThreadChild(num_list=list(range(6000000, 9000000)), name='th_3', ret_dic=ret_dic, ret_lock=ret_lock) 78 # thread_pool.append(th_3) 79 # 多线程计算结果: 830326785.5, 共消耗: 3.01 秒 80 # 单线程计算结果: 1484922580.2, 共消耗: 4.21 秒 81 82 # 多线程本质上还是在一个进程里做的资源分配优化,还没有利用到多进程,多核心计算的能力。 83 # 但是多线程的巨大优势是在遇到阻塞型函数,例如 API 调用,网络通信,文件读写的时候, 84 # 可以不被网络速度,硬盘速度耽误了程序其他部分的运算。 85 86 # 以上 Python 的多线程模块来实现计算提速,但是受限于在一个进程,也就是单核心上的运算
python多线程示例3,加锁(仅仅作为记录)
个人学习记录