信号量/死锁与递归锁/时间与Event/定时器和线程queue/GIL全局解释器锁

昨日复习:

1.线程:

(1)同一进程下的多个线程共享该进程的内存资源

(2)开启线程的开销远远小于开启进程

2.线程,进程,互斥锁的概念

https://mp.weixin.qq.com/s?__biz=MzIwNTc4NTEwOQ==&mid=2247484323&idx=1&sn=ea7e50be369f9992c6305555554a1252&chksm=972ad2d9a05d5bcfa9216d59cb063970f5bb52f262e657de9978db0250a90e84a9f49a8f0f7a&mpshare=1&scene=23&srcid=0106KZS0oSBKryf95uvWo3HU#rd

 3.守护进程和守护线程

守护线程:是守护的主线程的生命的周期,就是它所有的子线运行完才结束

守护进程:守护的是主进程的代码运行

4.生产者和消费者模型:

    模型就是编程的一种套路,来解决一种问题,你的任务有一个非常明显的特点,有一堆任务在造数据,一堆在取数据,两者通过解耦合的方式通过队列来提升效率互相不用等,这样造数据和取数据可以提升效率一直在造和取 ,类似快递柜

今日内容:

一:信号量

本质也是种一个锁,有多个锁可以加;类似于公共厕所

from threading import Thread,Semaphore,current_thread
import time,random

def func():
    sm.acquire()                    #开启
    print('%s is wcing'%current_thread().getName())
    time.sleep(random.randint(1,5))
    sm.release()                     #释放

if __name__ == '__main__':
    sm=Semaphore(5)                 #类似于5把钥匙 
    for i in range(23):
        t=Thread(target=func)
        t.start()

结果是:
Thread-1 is wcing
Thread-2 is wcing
Thread-3 is wcing
Thread-4 is wcing
Thread-5 is wcing
Thread-6 is wcing
Thread-7 is wcing
Thread-8 is wcing
Thread-9 is wcing
Thread-10 is wcing
Thread-11 is wcing
Thread-12 is wcing
Thread-13 is wcing
Thread-14 is wcing
Thread-15 is wcingThread-16 is wcing

Thread-17 is wcing
Thread-18 is wcingThread-19 is wcing
Thread-20 is wcing

Thread-21 is wcing
Thread-22 is wcing
Thread-23 is wcing

二:死锁与递归锁

锁套锁用递归锁,除非全部解锁其他才可以抢,也就是它的上面计数为0

死锁:

from threading import Thread,Lock
import time

mutexA=Lock()
mutexB=Lock()

class Mythread(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self) -> None:
        self.f1()
        self.f2()
    def f1(self):
        mutexA.acquire()
        print('%s抢到了A锁'%self.name)

        mutexB.acquire()
        print('%s抢到了B锁'%self.name)
        mutexB.release()
        mutexA.release()

    def f2(self):
        mutexB.acquire()
        print('%s抢到了B锁'%self.name)
        time.sleep(0.1)
        mutexA.acquire()
        print('%s抢到了A锁'%self.name)
        mutexA.release()
        mutexB.release()

if __name__ == '__main__':
    t1=Mythread('线程1')
    t2=Mythread('线程2')
    t3=Mythread('线程3')
    t4=Mythread('线程4')
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    print('主线程')

结果:
线程1抢到了A锁
线程1抢到了B锁
线程1抢到了B锁
线程2抢到了A锁
主线程

程序停止在原地

解决办法-----递归锁

from threading import Thread,RLock,Lock
import time

mutexA = mutexB = RLock()           #Rlock类似于一个人使用一个门中的多个厕所:一个人拿到钥匙后mutex.acquire,就会在他身上标记一个数字,直到他身上的数字为0时下一个才可使用 

class Mythread(Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name

    def run(self) -> None:
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print("%s 抢到了A锁" %self.name)

        mutexB.acquire()
        print("%s 抢到了B锁" %self.name)
        mutexB.release()

        mutexA.release()


    def f2(self):
        mutexB.acquire()
        print("%s 抢到了B锁" % self.name)
        time.sleep(0.1)

        mutexA.acquire()
        print("%s 抢到了A锁" % self.name)
        mutexA.release()

        mutexB.release()

if __name__ == '__main__':
    t1 = Mythread("线程1")
    t2 = Mythread("线程2")
    t3 = Mythread("线程3")
    t4 = Mythread("线程4")

    t1.start()
    t2.start()
    t3.start()
    t4.start()
    print("主线程")
结果是:
线程1 抢到了A锁
线程1 抢到了B锁
线程1 抢到了B锁
主线程
线程1 抢到了A锁
线程2 抢到了A锁
线程2 抢到了B锁
线程2 抢到了B锁
线程2 抢到了A锁
线程4 抢到了A锁
线程4 抢到了B锁
线程4 抢到了B锁
线程4 抢到了A锁
线程3 抢到了A锁
线程3 抢到了B锁
线程3 抢到了B锁
线程3 抢到了A锁

三:时间与Event

底层维护了一个全局变量的,默认的是False

一个线程运行完再运行另外一个程序:

from threading import Event,Thread,current_thread
import time
e=Event()   #全局的变量,默认是False

def f1():
    print('%s 运行'%current_thread().name)
    time.sleep(3)
    e.set()  #把全局变量改为True
    #e.clear()把全局变量改为False    e.is_set() 是否是set过  就是是否是True

def f2():
    e.wait()
    print('%s 运行'%current_thread().name)

if __name__ == '__main__':
    t1=Thread(target=f1)
    t2=Thread(target=f2)
    t1.start()
    t2.start()
结果是:
Thread-1 运行
Thread-2 运行

例子2~红绿灯模拟

from threading import Thread,Event,current_thread
import time,random

e=Event()

def task1():
    while True:
        e.clear()
        print('红灯亮')
        time.sleep(2)

        e.set()
        print('绿灯亮')
        time.sleep(3)

def task2():
    while True:
        if e.is_set():
            print('%s 走你'%current_thread().name)
            break
        else:
            print('%s等灯'%current_thread().name)
            e.wait()

if __name__ == '__main__':
   Thread(target
=task1).start() while True: time.sleep(random.randint(1,3)) Thread(target=task2).start() 结果是:

红灯亮
Thread-2等灯
绿灯亮
Thread-2 走你
Thread-3 走你
红灯亮
Thread-4等灯
绿灯亮Thread-4 走你

四:定时器和线程queue

定时器

from threading import Timer
def hello(n):
    print('hello world',n)
t=Timer(3,hello,args=(1111,))   时间,函数hello,还可以传参
t.start()
结果是:
hello world 1111

线程queue

import  queue
#队列(先进先出)
q=queue.Queue(3)
q.put(111)
q.put(222)
q.put(333)
print(q.get())
print(q.get())
print(q.get())
#结果:111,2,2,333

#堆栈(先进后出)
q=queue.LifoQueue(3)
q.put(111)
q.put(222)
q.put(333)
print(q.get())
print(q.get())
print(q.get())
#结果是:333,222,111

#优先级队列
q=queue.PriorityQueue(3)
q.put((1,111))   #里面放一个小元组,第一个是取出的顺序
q.put((5,222))
q.put((-1,333))
print(q.get())
print(q.get())
print(q.get())
#结果是:
(-1, 333)
(1, 111)
(5, 222)

五:GIL全局解释器锁******

cpython解释器同一进程下的多个线程,同一时刻只能有一个线程执行,不能同时进行,CPU多核优势用不上

六:协程

1.单个线程下应用程序自己实现并发的概念,操作系统的并发只是针对进程而言‘如果遇到io行为会被操作系统认为’整体是io而拿走cup而停在原地,也就是用不上多核的优势的。

2.要实现多个任务并发的概念:

  1.开4个进程,每个进程1个线程

  2.开2个进程,每个进程开2个线程

  3.开一个进程,应用程序控制切数据,在1个线程下快速切

原文地址:https://www.cnblogs.com/dayday-up-a/p/14311798.html