• day36


    死锁与递归锁:
    回顾之前的知识点,在介绍锁的时候跟大家提到过虽然锁只有acquire(加锁)和release(解锁)两种方式,但是还是不建议大家自己手动上锁而是用已经封装好的结构,有两个原因,
    首先第一点是因为封装好的模块使用起来更加方便,第二点就是自己在使用锁的时候很容易造成逻辑上的一些错误,接下来就为大家介绍死锁和递归锁

    死锁问题:线程在调用锁的时候会强行变成串行,但是两个线程在调用锁的时候就会可能出现“撞车”现象,两个线程绑定了锁的同时又需要对方的锁,这样就产生了拿不到还不放手的情况,线程被卡在当前状态。
    from threading import Thread, Lock
    import time


    mutexA = Lock()
    mutexB = Lock()
    class MyThead(Thread):
    def run(self):
    self.func1()
    self.func2()

    def func1(self):
    mutexA.acquire()
    print('%s 抢到A锁'% self.name) # 获取当前线程名
    mutexB.acquire()
    print('%s 抢到B锁'% self.name)
    mutexB.release()
    mutexA.release()

    def func2(self):
    mutexB.acquire()
    print('%s 抢到B锁'% self.name)
    time.sleep(2)
    mutexA.acquire()
    print('%s 抢到A锁'% self.name) # 获取当前线程名
    mutexA.release()
    mutexB.release()


    if __name__ == '__main__':
    for i in range(10):
    t = MyThead()
    t.start()

    递归锁:见名知其意,就是递归的锁定和解锁,递归锁有一个特点可以被连续的上锁以及解锁,但是只能被第一个拿到它的人进行这种操作 ,的内部有一个计数器 每acquire一次计数加一 每realse一次计数减一只要计数不为0 那么其他人都无法抢到该锁。
    那么根据这种锁的特点我们就能完美解决上面死锁的问题。

    导入Rlock模块,将两个实例化融合为一个,也就是mutexA = mutexB = RLock()

    信号量:
    信号量是一系列概念的统称,在不同的地方有不同的所指,在并发编程中信号量的知识领域就是锁。

    如果我们把互斥锁看做为一把锁头,那么信号量就是多把锁头的一个集合体,它们能同时为多个线程提供服务。

    sm = Semaphore(5) # 括号内写数字 写几就表示有几把锁 调用时与互斥锁使用方式相同也是加锁和解锁,其实也可以理解为锁的复数。

    Event事件:
    一些进程/线程需要等待另外一些进程/线程运行完毕之后才能运行,类似于发射信号一样。

    通过导入event模块,调用其中set()和 wait()方法完成信号的发射和等待接收等过程。

    线程q:
    同一个进程下的多线程运行的时候数据是共享的,那为什么我们还需要使用队列呢,之前我们提到过队列的实质是管道+锁的形式,所以我们使用队列的根本目的还是为了保证数据的安全性。

    对于queue实例化出来的队列除了队列常有的方法之外,还有一个颠覆性的设置就是后进先出式
    q = queue.LifoQueue() 括号内设置队列大小
    还有就是优先级设置
    q = queue.PriorityQueue()通过这种方式实例化得到的对象我们为其传一个元组作为参数,元组的第一个元素是优先级标识,第二个元素是数据本身,标识越小优先级越高。

    进程池和线程池:
    我们来回顾之前的TCP并发的完成步骤,首先我们接触了socketsever模块,然后又接触了多进程以及多线程的两种方法,但是无论是多开线程还是多开进程都需要耗费资源,虽然线程占用的资源要比进程还要小,但是总的来说还是在一定程度上耗费的,当并发量小的时候这种情况并不那么明显,但是当并发量大的时候这种资源的占用就很明显了。我们是不可能做到无限制的开设进程和线程的因为计算机硬件的资源跟不上,所以我们的解决方案应该在于保证计算机硬件安全的前提下最大的利用资源。

    由这种思想我们抽象出池的概念,首先说什么是池

    作为浸淫汉语一道多年的我们来说池就是一个容器,而通过使用池看来,池是用来保证计算机硬件安全的情况下最大限度的利用计算机
    它降低了程序的运行效率但是保证了计算机硬件的安全 从而让你写的程序能够正常运行。

    池子的使用非常的简单你只需要将需要做的任务往池子中提交即可 自动会有人来服务你。

    了解了池的概念之后让我们来了解一下异步回调机制

    任务的提交方式
    同步:提交任务之后原地等待任务的返回结果 期间不做任何事
    异步:提交任务之后不等待任务的返回结果 执行继续往下执行
    返回结果如何获取???
    异步提交任务的返回结果 应该通过回调机制来获取
    回调机制
    就相当于给每个异步任务绑定了一个定时炸弹
    一旦该任务有结果立刻触发爆炸

    进程:资源单位
    线程:执行单位
    协程:这个概念完全是程序员自己意淫出来的 根本不存在
    单线程下实现并发
    我们程序员自己再代码层面上检测我们所有的IO操作
    一旦遇到IO了 我们在代码级别完成切换
    这样给CPU的感觉是你这个程序一直在运行 没有IO
    从而提升程序的运行效率

  • 相关阅读:
    python基础 列表生成式
    docker 基础
    xpath例子
    redis删除以什么开头的key
    redis 关闭持久化
    python爬虫 保存页面
    python爬虫操作cookie
    SQl函数的写法
    加料记录(大屏幕)
    ios 调试
  • 原文地址:https://www.cnblogs.com/Jicc-J/p/12790509.html
Copyright © 2020-2023  润新知