zoukankan      html  css  js  c++  java
  • 线程(中)

    一、线程锁

    from threading import Thread,Lock
    
    l = Lock()  #实例化一个锁对象
    x = 0
    def task():
        global x
        l.acquire()  # 拿钥匙
        for i in range(100000):  #252990  出现了运算错误  由于三个线程抢占cpu导致的,所以我们需要给他加锁
            x +=1
        l.release()  #还钥匙   
    
    if __name__ == '__main__':
        t1 = Thread(target=task)
        t2 = Thread(target=task)
        t3 = Thread(target=task)
    
    l_t = [t1,t2,t3]
    for t in l_t:
        t.start()
    t.join()
    print(x)
    
    '''
    300000   这样结果就再也没有变过
    '''

    二、死锁和递归锁


    死锁:

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

    举个栗子:三个人吃面

    from threading import Thread,Lock
    import time
    
    chopsticks_lock = Lock()  #实例化一个筷子锁
    noodles_lock = Lock()    #实例化一个面条锁
    def eat1(name):  #开启第一个线程
        chopsticks_lock.acquire()  #给筷子加锁
        print(f"{name }--抢到了筷子")
        noodles_lock.acquire()   #给面条加锁
        print(f"{name }--抢到了面条")
        print(f"{name }--在吃面")
        chopsticks_lock.release()  #还钥匙
        noodles_lock.release()    #还钥匙
    
    
    def eat2(name):  #开启第二个线程
        noodles_lock.acquire()  # 给面条加锁
        print(f"{name}--抢到了面条")
        time.sleep(1)
        chopsticks_lock.acquire()  # 给筷子加锁
        print(f"{name }--抢到了筷子")
        print(f"{name }--在吃面")
        chopsticks_lock.release()  # 还钥匙
        noodles_lock.release()  # 还钥匙
    
    
    if __name__ == '__main__':
        l_name = ['线程1','线程2','线程3']   #定义一个吃面的人的列表
        for name in l_name:
            t1 = Thread(target=eat1,args=(name,))   #实例化第一个线程
            t2 = Thread(target=eat2,args=(name,))   #实例化第二个线程
            t1.start()
            t2.start()
    
    
    '''
    线程1--抢到了筷子
    线程1--抢到了面条
    线程1--在吃面
    线程1--抢到了面条
    线程2--抢到了筷子
    '''
    #这样就造成了死锁问题,杨蓬蓬--抢到了面条,王文彬--抢到了筷子,导致两个人都吃不了面,只有同时拿到面条课筷子才能吃面
    '''
    线程2拿到了(锁头1-筷子)想要往下执行需要(锁头2-面条)
    线程1拿到了(锁头2-面条)想要往下执行需要(锁头1-筷子),
    互相都拿到了彼此想要往下执行的必需条件,互相都不放手里的锁头.
    '''

    用递归锁解决死锁问题:

    递归锁:

    ​ 在同一个线程内可以被多次acquire

    ​ 就上面三个人吃面的例子,我们所说的死锁也就是带有筷子锁和面条所得一串锁,只要一串锁拿走了,其他人就拿不到锁。

    from threading import Thread,Lock,RLock
    import time
    chopsticks_lock = noodles_lock = RLock()  #实例化一个递归锁
    def eat1(name):  #开启第一个线程
        chopsticks_lock.acquire()  #给筷子加锁
        print(f"{name }--抢到了筷子")
        time.sleep(1)
        noodles_lock.acquire()   #给面条加锁
        print(f"{name }--抢到了面条")
        print(f"{name }--在吃面")
        chopsticks_lock.release()  #还钥匙
        noodles_lock.release()    #还钥匙
    
    
    def eat2(name):  #开启第二个线程
        noodles_lock.acquire()  # 给面条加锁
        print(f"{name}--抢到了面条")
        time.sleep(1)
        chopsticks_lock.acquire()  # 给筷子加锁
        print(f"{name }--抢到了筷子")
        print(f"{name }--在吃面")
        chopsticks_lock.release()  # 还钥匙
        noodles_lock.release()  # 还钥匙
    
    
    if __name__ == '__main__':
        l_name = ['线程1','线程2','线程3']   #定义一个吃面的人的列表
        for name in l_name:
            t1 = Thread(target=eat1,args=(name,))   #实例化第一个线程
            t2 = Thread(target=eat2,args=(name,))   #实例化第二个线程
            t1.start()
            t2.start()
    '''
    线程1--抢到了筷子
    线程1--抢到了面条
    线程1--在吃面
    线程1--抢到了面条
    线程1--抢到了筷子
    线程1--在吃面
    线程2--抢到了筷子
    线程2--抢到了面条
    线程2--在吃面
    线程2--抢到了面条
    线程2--抢到了筷子
    线程2--在吃面
    线程3--抢到了筷子
    线程3--抢到了面条
    线程3--在吃面
    线程3--抢到了面条
    线程3--抢到了筷子
    线程3--在吃面
    '''

    1|3三、信号量(Semaphore)


    规定几个线程一同运行,就必须几个线程一同运行,不能多,例如KTV只能一次进4个人,只有有人走了,其他人才能进去。那我们就来举一个KTV的例子

    from threading import Thread,Semaphore
    import time
    
    def KTV(name):
        sm.acquire()
        print(f"{name}走进了KTV")
        time.sleep(2)
        print(f"{name}走出了KTV")
        time.sleep(4)
        sm.release()
    
    if __name__ == '__main__':
        sm = Semaphore(4)  #规定一次只能有4个人进入KTV
        for i in range(15):
            t = Thread(target=KTV,args=(i+1,))
            t.start()
            
            
    '''
    1走进了KTV
    2走进了KTV
    3走进了KTV
    4走进了KTV
    
    1走出了KTV
    4走出了KTV
    2走出了KTV
    3走出了KTV
    ......
    5走进了KTV
    7走进了KTV
    6走进了KTV
    8走进了KTV
    '''

    四、GIL


    在Cpython解释器中有一把GIL锁(全局解释器锁),GIl锁本质是一把互斥锁。导致了同一个进程下,同一时间只能运行一个线程,无法利用多核优势.同一个进程下多个线程只能实现并发不能实现并行.

    为什么要有GIL?
    因为cpython自带的垃圾回收机制不是线程安全的,所以要有GIL锁.

    计算密集型 :推荐使用多进程
    每个都要计算10s
    多线程
    在同一时刻只有一个线程会被执行,也就意味着每个10s都不能省,分开每个都要计算10s,共40.ns
    多进程
    可以并行的执行多个线程,10s+开启进程的时间

    IO密集型: 推荐使用多线程
    4个任务每个任务90%大部分时间都在io.
    多线程
    可以实现并发,每个线程io的时间不咋占用cpu, 10s + 4个任务的计算时间
    多进程
    可以实现并行,10s+1个任务执行的时间+开进程的时间

    下面我们就来看这样一个例子:

    '''计算密集型'''
    #推荐使用多进程
    from threading import Thread
    from multiprocessing import Process
    import time
    
    def task():
        x = 0
        for i in range(10000000):
            x *= i
    
    
    if __name__ == '__main__':
        list = []
        start = time.time()
        for i in range(4):
            # p = Process(target=task) #实例化一个子进程
            # list.append(p)
            # p.start()
            t = Thread(target=task)
            list.append(t)
            t.start()
        for m in list:
            m.join()
        end= time.time()
        # print('多进程',end-start) #多进程 2.8643341064453125
        print('多线程', end-start)  #多线程 3.020913600921631
    '''看这个时间你就会一目了然'''
    from threading import Thread
    from multiprocessing import Process
    import time
    
    def task():
        time.sleep(2)
        print('哈哈哈!好好学习天天向上!!!')
    
    
    if __name__ == '__main__':
        list = []
        start = time.time()
        for i in range(4):
            p = Process(target=task) #实例化一个子进程
            list.append(p)
            p.start()
            # t = Thread(target=task)
            # list.append(t)
            # t.start()
        for m in list:
            m.join()
        end= time.time()
        print('多进程',end-start) #多进程 3.662198781967163
        # print('多线程', end-start)  #多线程 2.0046467781066895
    '''看这个时间你就会一目了然''' 
  • 相关阅读:
    C#磁吸屏幕窗体类库
    准备
    我写的诗
    How to turn off a laptop keyboard
    How to tell which commit a tag points to in Git?
    Why should I care about lightweight vs. annotated tags?
    How to get rid of “would clobber existing tag”
    Facebook, Google and Twitter threaten to leave Hong Kong over privacy law changes
    The need for legislative reform on secrecy orders
    Can a foreign key be NULL and/or duplicate?
  • 原文地址:https://www.cnblogs.com/lulingjie/p/11545531.html
Copyright © 2011-2022 走看看