python多线程示例2,加锁(仅仅作为记录)

 1 import threading
 2 
 3 # 多线程本质上是在一个 Python 程序里做的一个资源再分配,把几段代码的运行顺序进行先后调整达到 CPU 资源利用的最大化。
 4 # 但是这么做的一个缺点就是资源竞争Resource Contention,意思就是有可能几段代码同时在读写一个参数的时候,把这个参数的数值搞混。
 5 # 所以在多线程共享资源的情况下,需要在共享资源外部添加锁 Lock。
 6 
 7 # 直接继承线程类,然后覆盖继承类函数的方法
 8 class ThreadChild(threading.Thread):
 9     # 初始化 init: 通常继承线程类会扩写父类的初始化,来传递参数等。
10     def __init__(self, times, name, ret_dic, ret_lock):
11         # 扩写父类的初始化,首先调用父类的初始化
12         threading.Thread.__init__(self)
13         self.times = times
14         self.name = name
15         self.ret_dic = ret_dic
16         self.ret_lock = ret_lock
17         return
18     # 运行 run: 这是一个必须要覆盖的函数。启动线程调用的 start() 函数就是运行这个函数,这里是需要运行的核心代码。
19     def run(self):
20         # 覆盖重写函数 run
21         for i in range(self.times):
22             print(self.name + ' run: ' + str(i))
23         self.ret_lock.acquire()# 锁住, 锁住之后的代码将只能被一个线程执行下去,直到开锁
24         # 进入有可能竞争的共享资源,锁住
25         self.ret_dic[self.name] = self.name + " finished with " + str(self.times) + " times printed"
26         # 共享资源读写结束,开锁
27         self.ret_lock.release()# 开锁, 开锁之后,被锁住的资源和代码行又可以重新被其他线程读写
28         return
29 
30 if __name__ == '__main__':
31 
32     thread_pool = []
33     ret_dic = {}
34     # 锁类 Lock: 在线程中需要读写一个共享资源的时候,通过锁类来锁住资源,防止另外的线程读写修改。
35     # 这里在主程序中创建了一个锁 ret_lock, 并且传入了两个线程中。
36     # 这个锁本身是可以在多个线程中共享的,因为锁本身不存在资源竞争的问题,否则就没有意义了。
37     ret_lock = threading.Lock()
38     th_1 = ThreadChild(times=3, name='th_1', ret_dic=ret_dic, ret_lock=ret_lock)
39     th_2 = ThreadChild(times=5, name='th_2', ret_dic=ret_dic, ret_lock=ret_lock)
40     thread_pool.append(th_1)
41     thread_pool.append(th_2)
42 
43     # 非阻塞 start()
44     for th in thread_pool:
45         th.start()
46 
47     # 阻塞 join()
48     for th in thread_pool:
49         th.join()
50 
51     print(ret_dic)
52 
53     # 锁类 Lock: 在线程中需要读写一个共享资源的时候,通过锁类来锁住资源,防止另外的线程读写修改。
54     #           这里在主程序中创建了一个锁 ret_lock, 并且传入了两个线程中。
55     #           这个锁本身是可以在多个线程中共享的,因为锁本身不存在资源竞争的问题,否则就没有意义了。
56     # 锁住 Acquire: Acquire() 是锁的一个函数,表示获得资源,也可以表示锁住资源。在这个函数之后的代码将只能被一个线程执行下去,直到开锁。
57     # 开锁 Release: Release() 是锁的一个函数,表示释放资源,也可以表示开锁。开锁之后,被锁住的资源和代码行又可以重新被其他线程读写,运行。
58 
59     # 全局变量也是 Python 程序的共享资源,在多线程运算中,接触到全局变量的地方都需要加锁,或者也可以直接把锁变成全局变量:
60     # import threading
61     # glob_lock = threading.Lock()
62     # glob_a = 100
63     # def increase_by_a(num): # 不好的例子,虽然对全局变量加了锁,但是在函数内部运用了全局变量
64     #     glob_lock.acquire()
65     #     result = glob_a + num
66     #     glob_lock.release()
67     #     return result
68     # if __name__ == '__main__':
69     #     print(increase_by_a(100)) # 返回 200
70     #
71     #     glob_lock.acquire()
72     #     glob_a += 1
73     #     glob_lock.release()
74     #
75     #     print(increase_by_a(100)) # 返回 201,glob_a的改变破坏了函数 increase_by_a 的一致性
76     # 这里的锁是在全局变量中的,并且锁住了一个全局变量。
77     # 但是我们会发现,两次调用 increase_by_a 函数的过程中,
78     # 返回数值因为一个全局变量而变化了,尽管在函数传入的参数是一致的,这就破坏了函数的一致性:
79     #     函数的一致性:每次在同一个函数传入相同的参数,返回相同的结果
80     # 因此,尽量在函数中避免调用全局变量,或全局锁,以防破坏函数的一致性。
个人学习记录
原文地址:https://www.cnblogs.com/jeshy/p/15234059.html