Python多线程编程学习笔记

Python多线程编程学习笔记

写在前面

1. 多进程

  1. 多任务

    1. 多任务的优势:充分利用CPU资源,提高程序的执行效率
    2. 多任务是指在同一时间内执行多个任务
    3. 多任务的表现形式
      • 并发:在一段时间内交替去执行多个任务
      • 并行:在一段时间内真正的同时一起执行多个任务
  2. 进程

    1. 进程(Process)是资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位
    2. 一个程序至少有一个进程,程序是静态的,进程是动态的
  3. 多进程完成多任务

    1. p = multiprocessing.Process(target, name, group)

    2. p.start()启动进程

    3. 测试

      from multiprocessing import Process
      import time
      
      
      # 唱歌
      def sing():
          for i in range(3):
              print('唱歌...')
              time.sleep(0.5)
      
      
      # 跳舞
      def dance():
          for i in range(3):
              print('跳舞...')
              time.sleep(0.5)
      
      
      if __name__ == '__main__':
          p1 = Process(target=sing)
          p2 = Process(target=dance)
      
          p1.start()
          p2.start()
      
  4. 进程执行带有参数的任务

    1. args参数的使用

    2. kwargs参数的使用

      from multiprocessing import Process
      import time
      import os
      
      
      # 唱歌
      def sing(num):
          print('唱歌进程的pid:', os.getpid())
          print('唱歌父进程的pid:', os.getppid())
          for i in range(num):
              print('唱歌...')
              time.sleep(0.5)
      
      
      # 跳舞
      def dance(num2):
          print('跳舞进程的pid:', os.getpid())
          print('跳舞父进程的pid:', os.getppid())
          for i in range(num2):
              print('跳舞...')
              time.sleep(0.5)
      
      
      if __name__ == '__main__':
          print('主进程的pid:', os.getpid())
          p1 = Process(target=sing, args=(5,))
          p2 = Process(target=dance, kwargs={'num2': 2})
      
          p1.start()
          p2.start()
      
  5. 获取进程的编号

    1. 获取当前进程的编号:os.getpid()
    2. 获取当前父进程的编号:os.getppid()
  6. 进程的注意点

    1. 主进程会等待所有的子进程执行结束后再结束

    2. 设置守护主进程:主进程不会等待子进程结束就会结束

      子进程对象.daemon = True

2. 多线程

  1. 为什么要使用多线程:

    进程是分配资源的最小单位,一旦创建一个进程就会分配一定的资源。线程是程序执行的最小单位,一个进程中最少有一个线程来负责执行程序。线程自己不拥有系统资源,它可以与同属一个进程的其他线程共享进程所拥有的全部资源。

  2. 多线程完成多任务:跟进程一毛一样,只不过模块不一样。

    from threading import Thread

  3. 线程执行带有参数的任务:跟进程一毛一样

  4. 主线程和子线程的结束顺序:也跟进程一毛一样

    只不过设置守护线程的方法有两种:

    1. 在创建的时候,传递daemon参数
    2. 创建后,设置daemon
  5. 线程间的执行顺序

    1. 线程之间的执行是无序的,由CPU调度
    2. 获取当前的线程信息:threading.current_thread()
  6. 进程和线程对比

    1. 关系对比:

      1. 线程是依附在进程里面的,没有进程就没有线程
      2. 一个进程默认提供一条线程,进程可以创建多个线程
    2. 区别对比:

      1. 创建进程的资源开销要比创建线程的资源开销要大
      2. 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
      3. 线程不能够独立执行,必须依存在进程中
    3. 优缺点对比:

      1. 进程优缺点:

        优点:可以用多核

        缺点:资源开销大

      2. 线程优缺点:

        优点:资源开销小

        缺点:不能使用多核

3. 补充

  1. join:等待该线程执行完之后,才接着运行主线程后面的语句。
  2. 线程的返回是不能用return的,也就是说多线程的时候,不能通过return获取函数的返回值,需要传入一个记录返回值的列表,然后将函数的结果放入列表中。
  3. GIL 限制了 Python 多线程的性能不会像我们预期的那样。GIL:全局解释器锁,Global Interpreter Lock。GIL参考链接参考链接2
    • 我们该如何解决GIL锁的问题呢?
      1. 更换cpython为jpython(不建议)
      2. 使用多进程完成多线程的任务
      3. 在使用多线程可以使用c语言去实现
    • 什么时候会释放GIL?
      1. 遇到像 i/o操作这种 会有时间空闲情况 造成cpu闲置的情况会释放Gil
      2. 会有一个专门ticks进行计数 一旦ticks数值达到100 这个时候释放Gil锁 线程之间开始竞争Gil锁(说明: ticks这个数值可以进行设置来延长或者缩减获得Gil锁的线程使用cpu的时间)
    • 互斥锁和Gil锁的关系?
      1. Gil锁 : 保证同一时刻只有一个线程能使用到cpu
      2. 互斥锁 : 多线程时,保证修改共享数据时有序的修改,不会产生数据修改混乱
  4. 互斥锁threading.Lock(),执行时需要lock.acquire(),结束后需要lock.release(),这样有锁的线程才能操作。

我的CSDN:https://blog.csdn.net/qq_21579045

我的博客园:https://www.cnblogs.com/lyjun/

我的Github:https://github.com/TinyHandsome

纸上得来终觉浅,绝知此事要躬行~

欢迎大家过来OB~

by 李英俊小朋友

原文地址:https://www.cnblogs.com/lyjun/p/14385317.html