线程(中)

线程(下)

一、线程锁

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 = ['杨蓬蓬','王文彬','闫佳怡']   #定义一个吃面的人的列表
    for name in l_name:
        t1 = Thread(target=eat1,args=(name,))   #实例化第一个线程
        t2 = Thread(target=eat2,args=(name,))   #实例化第二个线程
        t1.start()
        t2.start()


'''
杨蓬蓬--抢到了筷子
杨蓬蓬--抢到了面条
杨蓬蓬--在吃面
杨蓬蓬--抢到了面条
王文彬--抢到了筷子
'''
#这样就造成了死锁问题,杨蓬蓬--抢到了面条,王文彬--抢到了筷子,导致两个人都吃不了面,只有同时拿到面条课筷子才能吃面
'''
线程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 = ['杨蓬蓬','王文彬','闫佳怡']   #定义一个吃面的人的列表
    for name in l_name:
        t1 = Thread(target=eat1,args=(name,))   #实例化第一个线程
        t2 = Thread(target=eat2,args=(name,))   #实例化第二个线程
        t1.start()
        t2.start()
'''
杨蓬蓬--抢到了筷子
杨蓬蓬--抢到了面条
杨蓬蓬--在吃面
杨蓬蓬--抢到了面条
杨蓬蓬--抢到了筷子
杨蓬蓬--在吃面
王文彬--抢到了筷子
王文彬--抢到了面条
王文彬--在吃面
王文彬--抢到了面条
王文彬--抢到了筷子
王文彬--在吃面
闫佳怡--抢到了筷子
闫佳怡--抢到了面条
闫佳怡--在吃面
闫佳怡--抢到了面条
闫佳怡--抢到了筷子
闫佳怡--在吃面
'''

三、信号量(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():
    print('男生都是大猪蹄子呀')
    print('你觉得呢')
    print('我觉得是这样哦')
    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
'''看这个时间你就会一目了然'''
原文地址:https://www.cnblogs.com/yanjiayi098-001/p/11543419.html