zoukankan      html  css  js  c++  java
  • python全栈学习--day42

    线程

    什么是线程?

    线程是CPU调度的最小单位。而进程是资源分配的最小单位,进程和线程是什么关系?

      线程是在进程中的一个执行单位,多进程 本质上开启的这个进程里就有一个线程

      多进程 本质上开启的这个进程里就有一个线程

      多线程 单纯的在当前进程中开启了多个线程

    线程和进程的区别:

      线程的开启,销毁,任务切换的时间开销小

      在同一个进程中数据共享

      能实现并发,但不能脱离进程

      进程负责管理分配资源 线程负责执行代码

    GIL 锁  ---全局解释器锁

    同一时刻只能在有一个线程访问CPU----线程锁

    Cpython解释器 ----copy jpython

    python程序效率下降

    高计算型-----多线程会导致程序的效率下降

    高IO型的-----可以使用多线程

    多进程

    分布式计算-------celery

    import time
    from threading import Thread,currentThread,enumerate,activeCount
    
    def func():
        print('-->',currentThread())
        time.sleep(0.1)
        print(123)
    
    t = Thread(target=func)
    t.start()
    print(t.is_alive())
    print(t.getName())
    t.setName('t1')
    print(t.getName())
    # print(currentThread())
    # print(enumerate())  # 你启动的活着的线程数 + 1(主线程)
    print('-->',activeCount())  # 相当于len(enumerate())
    # 守护线程
    # 守护进程是等待主进程代码结束之后就结束
    # 守护线程是等待主线程都结束之后才结束
    

    import time
    from threading import Thread,Lock
    def func(lock):
        global n
        temp = n
        n = temp -1
    
    n = 100
    t_lst = []
    lock = Lock()
    for i in range(100):
        t = Thread(target=func,args=(lock,))
        t.start()
        t_lst.append(t)
    for t in t_lst:t.join()
    print(n)
    

     

    二、同步锁

    当多线程争夺锁时,允许第一个获得锁的线程进入临街区,并执行代码。所有之后到达的线程将被阻塞,只到第一个线程执行结束,退出临界区,并释放锁。

    多个线程抢占资源的情况:

    import time
    from threading import Thread
    def func():
        global n
        temp = n
        time.sleep(1)
        n = temp -1
     
    n = 100
    t_lst = []
    for i in range(100):
        t = Thread(target=func)
        t.start()
        t_lst.append(t)
    for t in t_lst:t.join()
    print(n)
    

      执行输出:99

    明明减少了100次,结果应该是0的。

    为啥是99呢?难度是GIL的问题,但GIL是计算CPU那一刻的锁

    下面开始具体分析:

    第一步,每个线程执行

    global n:temp =n 此时,temp等于100

     

    第二步:当线程设计到CPU计算时,向CPU发送请求。但是收到GIL的限制

    同一时刻,只能有一个线程计算。

    CPU计算结果后,返回给线程。线程赋值,并修改全局变量n。此时n=99,线程结束

     那么其他线程,也是做同样的操作。

    每个线程赋值n等于99。不管它已经是99了。

    上面的现象,出现了数据不安全的情况

    最后赋值了100次,都是n=99。所以最终结果是99

     怎么解决呢?加锁

    import time
    from threading import Thread,Lock
    def func(lock):
        global n
        lock.acquire()  #加锁
        temp = n
        n = temp -1
        lock.release()  #解锁
    
    n = 100
    t_lst = []
    lock = Lock()   #创建锁
    for i in range(100):
        t = Thread(target=func,args=(lock,))
        t.start()
        t_lst.append(t)
    for t in t_lst:t.join()     #等待所有子线程结束
    print(n)
    

     

    执行输出:0

    如果把计算和赋值拆开,就会出现数据不安全的情况

     

    下面写法,不用加锁,也可以得到0

    from threading import Thread
    
    def func():
        global n
        n -= 1
    
    n = 100
    for i in range(100):
        t = Thread(target=func)
        t.start()
    

      

    执行输出:0

    因为默认有一个GIL锁,所以每个线程都减等1。所以最终结果为0

    三、死锁与递归锁                                                            

    进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额

    所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁

    1
    2
    3
    4
    5
    6
    from threading import Lock
     
    lock = Lock()  # 在同一个线程中,能够被一个锁的多个acquire阻住,这种锁就叫做互斥锁
    lock.acquire()
    lock.acquire()
    lock.acquire()

    死锁,也叫互斥锁

    科学家吃面的问题

    要完成一件事情 需要两个必要因素
    要想吃到面,需要: 叉子,面
    资源的互相抢占的问题 —— 死锁

    四个人围着一张桌子,桌子上放着一碗面,碗里有一个叉子
    必须拿到叉子,才能吃面。
    每个人每次只能吃一口面,吃完就放回去,让下一个人吃。

     
     
  • 相关阅读:
    中国剩余定理及其扩展
    扩展欧几里得
    乘法逆元
    58-63用ssh远程连接linux系统
    148复习前一天的内容
    165-168函数
    Linux运维命令总结(-)
    177流程控制经典案例讲解
    170-176流程控制
    161【案例讲解】存储过程
  • 原文地址:https://www.cnblogs.com/haowen980/p/9047916.html
Copyright © 2011-2022 走看看