并发编程-3

并发编程-3

目录

  • 互斥锁
  • 线程理论
  • 创建线程的多种方式
  • 线程的相关方法
  • GIL全局解释锁

互斥锁

多个程序同时操作一份数据的时候很容易产生数据错乱!!!
为了避免数据错乱 我们需要使用互斥锁

  • 互斥锁的作用

    ​ 将并发变成串行 虽然牺牲了程序的执行效率但是保证了数据安全

  • 如何使用互斥锁

    from multiprocessing import Process, Lock
    mutex = Lock()
    mutex.acquire()  # 抢锁
    mutex.release()  # 释放锁
    
  • 互斥锁的应用场景

    ​ 互斥锁只应该出现在多个程序操作数据的地方 其他位置尽量不要加

  • 锁的类别

    类别 用途
    行锁 将一行的数据只能让一人读取
    表锁 将整个表的数据只让一个人读取
    乐观锁 都能查看数据,只要有一个人修改数据就放弃操作
    悲观锁 只要有一个人在操作数据时就直接上锁,直到操作完才释放

线程理论

  • 进程和线程

    单位 理解
    进程 资源单位 进程相当于是车间
    进程负责给内部的线程提供相应的资源
    线程 执行单位 线程相当于是车间里面的流水线
    线程负责执行真正的功能
  • 进程与线程的关系

    ​ 一个进程至少含有一个线程

    ​ 同一个进程下多个线程之间资源共享

  • 多进程与多线程的区别

    区别
    多进程 需要申请内存空间
    需要拷贝全部代码 资源消耗大
    多线程 不需要申请内存空间
    也不需要拷贝全部代码 资源消耗小

线程

  • 开设线程的两种方式

    from threading import Thread
    from multiprocessing import Process
    import time
    
    # def task(name):
    #     print(f'{name}正在运行')
    #     time.sleep(3)
    #     print(f'{name}运行结束')
    
    
    """
    开设线程不需要完整拷贝代码 所以无论什么系统都不会出现反复操作的情况 
    也不需要在启动脚本中执行 但是为了兼容性和统一性 习惯在启动脚本中编写
    """
    
    
    # t = Thread(target=task, args=('jason',))
    # t.start()
    # print('主线程')
    # if __name__ == '__main__':
    #     t = Thread(target=task, args=('jason',))
    #     t.start()
    #     print('主线程')
    
    
    class MyThread(Thread):
        def __init__(self, name):
            super().__init__()
            self.name = name
    
        def run(self):
            print(f'{self.name}正在运行')
            time.sleep(3)
            print(f'{self.name}运行结束')
    
    
    obj = MyThread('jason')
    obj.start()
    print('主线程')
    
  • 多线程实现TCP服务端并发

    与多进程实现TCP服务端并发相比,更加方便,所消耗的资源更少

  • join方法

    主线程等到子线程运行结束之后再运行
    from threading import Thread
    import time
    
    def task():
        print('正在执行')
        time.sleep(3)
        print('运行结束')
    
    
    t = Thread(target=task)
    t.start()
    t.join()
    print('主线程')
    
  • 同一个进程下线程间的数据共享

    from threading import Thread
    
    money = 1000
    
    
    def func():
        global money
        money = 666
    
    
    t = Thread(target=func)
    t.start()
    t.join()  # 确保线程运行完毕 再查找money 结果更具有说服性
    print(money)
    
  • 线程对象的相关方法

    1. 进程号

      ​ 同一个进程下开设的多个线程拥有相同的进程号

    2. 线程名

      from threading import Thread, current_thread
      current_thread().name
      主:MainThread	子:Thread-N
      
    3. 进程下的线程数

      ​ active_count()

  • 守护线程

    ​ 守护线程伴随着被守护的线程的结束而结束

    from threading import Thread
    import time
    
    def task():
        print('子线程运行task函数')
        time.sleep(3)
        print('子线程运行task结束')
    
    
    t = Thread(target=task)
    # t.daemon = True
    t.start()
    # t.daemon = True
    print('主线程')
    

    ​ 进程下所有的非守护线程结束 主线程(主进程)才能真正结束!!!

GIL全局解释器锁

  • 补充知识

    ​ python解释器也是由编程语言写出来的
    ​ Cpython 用C写出来的
    Jpython 用Java写出来的
    ​ Pypython 用python写出来的

    ​ 最常用的就是Cpython(默认)

  • GIL的本质

    ​ GIL的本质就是一把互斥锁

  • GIL存在的意义

    1. 使得同一个进程下的多个线程无法同时执行(关键)

    2. cpython解释器中垃圾回收机制不是线程安全的

  • GIL的理解

    GIL就是一把防止垃圾回收机制勿删的保护数据的互斥锁

    并不能代表写代码的时候所添加的互斥锁

    他们有本质上的区别,GIL是保护解释器层面的数据不会错乱

    而互斥锁是自己自行添加的,对自己的数据加以保护

posted @ 2022-08-10 20:50  Nirvana*  阅读(32)  评论(0)    收藏  举报