持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天
变量共享
这里有一段非常简单的代码
import threading
money = 1000
def run1():
global money
for i in range(100):
money -= 1
def run2():
global money
for i in range(100):
money -= 1
if __name__ == '__main__':
th1 = threading.Tbread(target=run1,name='a')
th2 = threading.Tbread(target=run2,name='b')
th1.join()
th1.join()
print(money)
得到的结果可以看出全局变量在两个线程内是可以互通的所以我们可以简化代码
import threading
money = 1000
def run1():
global money
for i in range(100):
money -= 1
if __name__ == '__main__':
th1 = threading.Tbread(target=run1,name='a')
th2 = threading.Tbread(target=run1,name='b')
th1.join()
th1.join()
print(money)
线程同步问题
import threading
money = 0
def run1():
global money
for i in range(10000000):
money += 1
if __name__ == '__main__':
th1 = threading.Tbread(target=run1,name='a')
th2 = threading.Tbread(target=run1,name='b')
th3 = threading.Tbread(target=run1,name='c')
th1.join()
th1.join()
print(money)
- 注意在这里如果全局变量的数据过大可能会导致最终的结果无法达到预期的值
即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。
相当于给你的线程加了一把锁:GIL(全局解释器锁)数据过大锁就会自动释放
python的底层只要用线程就会默认加锁
- 举个例子(如上图)
这里的n -= 1实际上是n = n-1,其实在这里的算式是两步,一个是减法一个是赋值,而 在python中有可能在执行的二步赋值的时候线程1会被线程2强制挤下去,这时线程1进入了就绪状态,而由于n没进行赋值,所以才会有结果的偏差(也就是全局变量过大时出现的结果偏差)
- 解决方法
由上述我们可知当一个线程在运行时我们可以将入口堵住,这样就可以等一个线程自己进入堵塞状态然后进行下一个线程
应用:只要有共享数据就要加一把锁
- 缺点
运行的速度会变慢
- 方法
因此我们要正确使用线程和进程:线程做的是耗时操作,而进程做的是计算密集型操作