Python的GIL和同步锁学习心得

问题抛出:求100一直减到0?

可以用常规的串行方式解决,这里就不讨论了。我们直接上手多线程同时计算100连续减到0。

import threading   # 导入线程模块

def func():

  global num

  # num -= 1    这个结果是正确的 0 

  temp = num              # 这个执行结果是99    为什么不是0?  答:对于num-=1  cpu处理速度非常快 而换成这种中间变量方式则增加了cpu处理时间 尤其是有阻塞的time.sleep

  time.sleep(0.1)   # 因为GIL导致Python每次只有一个线程在cpu上跑 

  num = temp - 1   # 因此每次cpu遇到阻塞就切换另一个线程,另一个线程也是如此。直到切换完100次 回到第一次的temp=100 执行100-1 剩下的99线程也是如此。

list_thread = []

num = 100

for i in range(100):                   # 创建100个线程

  t = threading.Thread(target=func)

  t.start()

  list_thread.append(t)

for t in list_thread:              # 让线程执行完了再打印最后的数字

  t.join()

print("End num:", num)

思考:对于本需求的抛出,那么Python就没有办法用多线程解决了吗?

答:有! 那就是用同步锁!

这需要引入同步锁

在代码num=100下面引入:

 lock = threading.Lock()  # 引入同步锁

在func中加入同步锁:

  lock.acquire()    # 加锁

  temp = num 

  time.sleep(0.1)

  num = temp - 1

  lock.release()  # 解锁

 加锁的目的就是告诉cpu:在我加锁的这段代码没有执行完之前不准切换。       这就解决了问题啦!

思考:既然加锁了那么就相当于程序变成了串行不允许cpu切换,这和多线程有啥关系?

答:没错!加锁确实是变成了串行,但是这只是其中加锁部分的代码变成了串行,对于没有加锁的代码而言依旧是多线程并行的。例如在加锁代码之前加入 print("ok"),还是多线程!一瞬间同时打印100个ok。

思考:GIL是把锁了,为什么还有整个同步锁?

答:两把锁功能不一样。GIL这把锁是Python语言的开发者设计的,目的是让同一时间只能有一个线程在Cpython解释器上执行,防止变量等公共资源被杂七杂八的线程共同使用。而同步锁是我们程序员自己设定的,目的是控制cpu要一直执行某段代码,不允许中途切换造成计算失误。

猜你喜欢

转载自www.cnblogs.com/Rophy/p/9132945.html