python高级进阶_26_多线程锁会遇到的问题总结

先看上一节的代码, 我们再改良下,看看是什么效果?

下边的代码,细心的小伙伴可以看出, 本来是多线程 却让你逼成单线程,

因为 在加锁和释放锁 都是在循环计算的外边,也就是 在线程一 执行完后 再执行 线程二,

import threading ,time

def work1():
    global num
    mutex.acquire()  # 上锁
    for i in range(100000):
        num += 1
    mutex.release()  # 开锁
    print("work"+str(num) )
def work2():
    global num
    mutex.acquire()   # 上锁
    for i in range(100000):
        num += 1
    mutex.release()  #释放
    print("work2 %s"%num)
if __name__=='__main__':
    mutex=threading.Lock()  # 创建一个锁对象
    num=0
    t1 = threading.Thread(target=work1)
    t1.start()     #线程1 运行
    t2 = threading.Thread(target=work2)
    t2.start() # 线程2 运行

我们改下下, 把锁加在计算里面 ,看看是什么效果?

import threading ,time

def work1():
    global num

    for i in range(100000):
        mutex.acquire()
        num += 1
        mutex.release()
    print("work"+str(num) )
def work2():
    global num
    for i in range(100000):
        mutex.acquire()
        num += 1
        mutex.release()
    print("work2 %s"%num)
if __name__=='__main__':
    mutex=threading.Lock()
    num=0
    t1 = threading.Thread(target=work1)
    t1.start()     #线程1 运行
    t2 = threading.Thread(target=work2)
    t2.start() # 线程2 运行
    print("main%d"%num)

打印结果为:
main 25083
work2 196207
work 200000

这样就可以他们两个一起执行 , 在关键点加,例如改变共享变量的地方。

当时我看到 这样结果 ,我有以下问题 ,你也会遇到的。

1. work1 为什么放到最后才给结果 ,难道不是work2放到最后
2. work2 执行结束后怎么是 196207 而不是 100000
3. 和轮询等待方式一样吗? 难道不消耗 cpu
4. 多线程的锁有执行顺序吗 ?
5.加锁的位置选择?
6. main 打印的为什么和其他都不一样

我们先分析下执行过程 ?

  1. 主线程运行下边的代码,生成一个锁对象,然后初始化num的值
    mutex=threading.Lock()
    num=0

  2. 主线程继续走, 遇到下边的代码 同时生成两个子线程
    现在为止 一共有三个线程他们同时在跑,一个是 主线程和两个子线程 , 主线程是不等子线程跑完再跑
    t1 = threading.Thread(target=work1)
    t1.start() #线程1 运行
    t2 = threading.Thread(target=work2)
    t2.start() # 线程2 运行

  3. 两个子线程 生成后,当遇到有加锁的地方,两个线程开始争夺控制权,争夺到的,立刻拿到了开锁的控制权,对其他的线程来说是关闭的,所以只能运行有锁控制权的代码(以下代码)
    for i in range(100000):
    mutex.acquire()
    num += 1
    mutex.release()

  4. 当运行一次 释放控制权的时候,他会通知其他线程,我的锁已经释放了,再继续争夺控制权, 这个过程是通知, 在等通知期间是休息的,不占用cpu 资源

  5. 主线程是不等子线程跑完再跑, 继续执行 print(“main%d”%num), 这个num 当时计算的结果是什么就是什么,

  6. 主线程执行完毕后,不会退出直到所有的子线程完成。

  7. 子线程循环执行后,当有一个线程执行完毕就会执行打印当前线程累加的值 print(“work2 %s”%num),所以他的结果是两个线程循环计算的结果不是单个线程的结果。

  8. 线程1 结束后, 线程二继续单线程的跑,直到结束 , 由于他们避免了同时操作一个值的过程,所以计算的值 是累加起来的 200000

1. work1 为什么放到最后才给结果 ,难道不是work2放到最后

答: 有可能work2抢占控制权比较多,他就先执行 打印出来了, 这个是随机的。

2. work2 执行结束后怎么是 196207 而不是 100000

答: 当线程结束后,就打印这个值,这个值是线程之间轮循累加的结果,不是单线程跑的结果。

3. 和轮询等待方式一样吗? 难道不消耗 cpu

答: 在一个线程抢占了锁, 其他线程是sleep 状态, sleep 不消耗资源,他释放锁的时候,会叫醒其他睡着的线程。

4. 多线程的锁有执行顺序吗 ?

答: 是随机的, 有操作系统调度算法决定。 他也有一个准则就是 雨露均沾。

5.加锁的位置选择?

答: 粒度越小越好, 在业务执行的点加 例如在改变全局变量的地方 , 就像上边的例子,当放到 for循环里面和外边差别很大

6. main 打印的为什么和其他都不一样

答: 主线程是不等子线程跑完再跑, 继续执行 print(“main%d”%num), 这个num 当时计算的结果是什么就打印什么,

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值