• python开发面试-20240715


    1、python GIL锁,以及如何避免

    1、使用多进程 multiprocesssing

    2、使用C扩展

    3、使用异步编程

    4、使用外部库如Numpy、Panda

    5、GIL优化:python版本升级,可能会进行优化

    2、python 内存回收

    Python 使用自动内存管理来回收不再使用的对象,这主要通过垃圾收集器(Garbage Collector,GC)来实现。Python 的垃圾收集器主要依赖于引用计数机制和循环垃圾收集机制。

    引用计数

    Python 中的每个对象都有一个引用计数,用来记录有多少个引用指向该对象。当一个对象的引用计数变为 0 时,意味着没有任何引用指向该对象,该对象可以被垃圾收集器立即回收。

    引用计数机制简单有效,但也有一些局限性:

    • 循环引用问题:如果两个或多个对象相互引用,它们的引用计数永远不会变为 0,即使它们不再被使用。
    • 内存泄漏:如果程序中存在无法访问到的对象,即使它们不再被使用,也不会被回收。

    循环垃圾收集

    为了解决循环引用问题,Python 使用了循环垃圾收集机制。这是一种基于标记-清除(Mark-and-Sweep)算法的垃圾收集方法。

    1. 标记阶段:垃圾收集器遍历所有可达的对象,并将它们标记为活跃的。
    2. 清除阶段:垃圾收集器遍历所有未被标记的对象,并将它们回收。

    Python 的循环垃圾收集器可以检测到循环引用,并能够回收这些无法通过引用计数机制回收的对象。

    垃圾收集器的触发

    Python 的垃圾收集器不是在每次对象不再使用时就立即触发,而是在以下情况下触发:

    • 程序显式调用 gc.collect() 函数。
    • 程序达到一定的内存使用阈值。
    • 程序启动时或退出前。

    3、单例模式,以及实现方法

    1. 1、使用模块
    2. Python 的模块本身就是一个单例。模块在第一次导入时会被初始化,之后再次导入时会使用已经初始化的模块。
    3. # my_singleton_module.py
    4. class Singleton:
    5. def __init__(self):
    6. self.value = 'I am a singleton'
    7. # 使用
    8. from my_singleton_module import Singleton
    9. singleton_instance = Singleton()
    10. 2、使用装饰器
    11. def singleton(cls):
    12. instances = {}
    13. def wrapper(*args, **kwargs):
    14. if cls not in instances:
    15. instances[cls] = cls(*args, **kwargs)
    16. return instances[cls]
    17. return wrapper
    18. @singleton
    19. class MyClass:
    20. def __init__(self):
    21. self.value = 'I am a singleton'
    22. # 使用
    23. instance1 = MyClass()
    24. instance2 = MyClass()
    25. print(instance1 is instance2) # True
    26. 3、使用类属性
    27. class Singleton:
    28. _instance = None
    29. def __new__(cls):
    30. if cls._instance is None:
    31. cls._instance = super(Singleton, cls).__new__(cls)
    32. return cls._instance
    33. def __init__(self):
    34. self.value = 'I am a singleton'
    35. # 使用
    36. instance1 = Singleton()
    37. instance2 = Singleton()
    38. print(instance1 is instance2) # True
    39. 4、使用元类
    40. class SingletonMeta(type):
    41. _instances = {}
    42. def __call__(cls, *args, **kwargs):
    43. if cls not in cls._instances:
    44. instance = super().__call__(*args, **kwargs)
    45. cls._instances[cls] = instance
    46. return cls._instances[cls]
    47. class Singleton(metaclass=SingletonMeta):
    48. def __init__(self):
    49. self.value = 'I am a singleton'
    50. # 使用
    51. instance1 = Singleton()
    52. instance2 = Singleton()
    53. print(instance1 is instance2) # True

    4、多进程,多线程,协程的区别。

    Python 支持多进程、多线程和协程三种并发执行的机制,它们各自有不同的特点和用途:

    多进程(Multiprocessing)

    • 定义:多进程是指操作系统为每个进程分配独立的内存空间,进程之间不共享内存。
    • 优点
      • 隔离性好:一个进程崩溃不会影响其他进程。
      • 利用多核CPU:可以充分利用多核处理器的计算能力,因为每个进程可以运行在不同的CPU核心上。
    • 缺点
      • 创建和销毁进程的开销大。
      • 进程间通信(IPC)复杂且成本高。
    • 适用场景:适合CPU密集型任务,或者需要隔离性的场景。

    多线程(Multithreading)

    • 定义:多线程是指在一个进程中并行运行多个线程,线程之间共享进程的内存空间。
    • 优点
      • 资源共享:线程间可以共享数据,这使得线程间通信更加容易。
      • 创建和切换开销小。
    • 缺点
      • Python中的全局解释器锁(GIL):在CPython实现中,由于GIL的存在,同一时刻只有一个线程可以执行Python字节码,这限制了多线程在CPU密集型任务中的并行性。
      • 线程安全问题:需要同步机制来避免竞态条件和数据不一致。
    • 适用场景:适合I/O密集型任务,或者需要共享内存资源的场景。

    协程(Coroutines)

    • 定义:协程是一种更轻量级的执行单元,它在用户态进行调度,而不是操作系统内核态。
    • 优点
      • 高效:协程的创建和切换开销非常小。
      • 非抢占式:协程的执行是协作式的,一个协程执行完成后主动让出控制权给另一个协程。
      • 适用于大量I/O操作:协程可以在等待I/O操作时挂起,让其他协程运行,提高效率。
    • 缺点
      • 调试困难:协程的调用栈可能不如线程和进程那样直观。
      • 错误处理:协程的错误可能会影响到整个程序的执行流程。
    • 适用场景:适合处理大量I/O密集型任务,如网络请求、文件操作等。

    总结

    • 多进程:适合CPU密集型任务,可以充分利用多核处理器,但进程间通信复杂。
    • 多线程:适合I/O密集型任务,线程间可以共享内存,但在CPython中由于GIL的限制,多线程在CPU密集型任务中的并行性受限。
    • 协程:适合大量I/O操作,可以在等待I/O时让出控制权,提高程序的响应性和效率。

    在Python中,可以使用multiprocessing模块来创建和管理多进程,使用threading模块来创建和管理多线程,使用asyncio库来创建和管理协程。协程在Python 3.5之后得到了原生支持,通过asyncawait关键字实现。

    5、什么是闭包

    1、外层方法的返回是对内部方法的调用

    6、常用的进程,进程池包

    from multiprocessing import Process
    from concurrent.futures import ProcessPoolExecutor

    7、Django生命周期

    web -> wsgi -> process_request -> process_view -> view -> process_response -> wsgi -> web

    8、中间件的执行顺序

    如果有多个中间件,ABCDE(C是视图),执行过程是

    执行ABDE的process_request

    执行view逻辑

    执行EDBA的process_response

    9、docker 怎么进入一个运行中的容器

    docker exec -it /bin/bash

    10、docker 怎么启动一个容器

    # 启动一个容器

    docker run -d --name new_container my_new_image

    # 进入一个运行中的容器

    docker exec -it my_container /bin/bash

    # 交付容器,创建一个新的镜像

    docker commit my_container my_new_image

    11、怎么让一个容器停止时,自动销毁

    docker run --rm -d --name my_container ubuntu sleep 60

    -rm:容器停止时自动销毁

    #

    # 在dockerfile中设置cmd

    FROM ubuntu
    # ... 其他指令 ...

    # 定义一个清理脚本
    COPY cleanup.sh /cleanup.sh
    RUN chmod +x /cleanup.sh

    # 设置容器退出时执行清理脚本
    CMD ["/cleanup.sh"]

    12、dockerfile 常用的命令

    1. FROM - 指定基础镜像,所有的构建过程都是基于这个镜像开始的。

      FROM ubuntu:18.04

    2. RUN - 执行命令,通常用于安装软件包或执行脚本。

      RUN apt-get update && apt-get install -y curl

    3. CMD - 容器启动时默认执行的命令。如果有多个 CMD 指令,只有最后一个会生效。

      CMD ["python", "app.py"]

    4. ENTRYPOINT - 容器启动时要运行的可执行文件,可以与 CMD 组合使用。

      ENTRYPOINT ["python"]

    5. EXPOSE - 声明容器运行时监听的端口,不会发布端口,只是作为文档说明使用。

      EXPOSE 80

    6. ENV - 设置环境变量。

      ENV PATH /usr/local/nginx/bin:$PATH

    7. ADD - 将文件、目录或远程文件URL添加到容器中。

      ADD source_file.txt /dest/path

    8. COPY - 类似于 ADD,但只支持本地文件的复制。

      COPY source_file.txt /dest/path

    9. VOLUME - 创建一个可以从本地主机或其他容器挂载的挂载点。

      VOLUME /data

    10. WORKDIR - 设置工作目录,即容器内部的当前目录。

      WORKDIR /app

    11. USER - 设置运行容器时的用户名或 UID。

      USER nobody

    12. ARG - 构建参数,可以在构建时通过 --build-arg 传递给 Docker。

      ARG VERSION=1.0

    13. ONBUILD - 设置触发器,当以当前镜像为基础镜像时,自动执行的指令。

      ONBUILD RUN echo "Hello, this is an ONBUILD trigger"

    14. STOPSIGNAL - 设置停止容器时使用的系统调用信号。

      STOPSIGNAL SIGKILL

    15. LABEL - 添加元数据到镜像,可以是键值对。

      LABEL maintainer="name@example.com"

    16. HEALTHCHECK - 设置健康检查命令,用于确定容器是否健康。

      HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1

    13、docker-compose 常用命令

    1. 启动服务: 使用 up 命令启动在 docker-compose.yml 文件中定义的所有服务。

      docker-compose up

    2. 启动服务(后台运行): 添加 -d 标志以在后台运行服务。

      docker-compose up -d

    3. 停止服务: 使用 down 命令停止所有由 docker-compose.yml 文件定义的服务,并移除容器、网络、卷和镜像。

      docker-compose down

    4. 查看服务状态: 使用 ps 命令查看所有服务的容器状态。

      docker-compose ps

    5. 查看日志: 使用 logs 命令查看服务的日志输出。

      docker-compose logs

    6. 重新启动服务: 使用 restart 命令重新启动服务。

      docker-compose restart

    7. 停止并移除容器: 使用 stop 命令停止服务中的所有容器。

      docker-compose stop

    8. 构建或重建服务: 使用 build 命令重新构建或构建服务。

      docker-compose build

    9. 拉取服务的镜像: 使用 pull 命令拉取服务的镜像。

      docker-compose pull

    10. 运行一次性命令: 使用 run 命令在服务的容器中运行一次性命令。

      docker-compose run myservice /bin/bash

    11. 查看服务详情: 使用 config 命令查看 docker-compose.yml 文件的配置详情。

      docker-compose config

    12. 扩展服务: 使用 scale 命令扩展服务的容器数量。

      docker-compose up --scale myservice=3

    13. 列出所有容器: 使用 ls 命令列出所有由 docker-compose.yml 文件管理的容器。

      docker-compose ls

    14. 推送服务的镜像: 使用 push 命令推送服务的镜像到远程仓库。

      docker-compose push

    15. 创建服务的网络: 使用 create-network 命令创建网络。

      docker-compose create-network

    16. 创建并启动服务: 使用 up 命令创建并启动服务,如果服务已经存在则只启动服务。l

      docker-compose up --create

    14、redis的数据类型

    string list set zset hash

  • 相关阅读:
    flume框架原理
    如何使用 Loadgen 来简化 HTTP API 请求的集成测试
    1、error LNK2019: 无法解析的外部符号“struct ********“
    【代码随想录】算法训练营 第十一天 第五章 栈与队列 Part 2
    RS485通讯方式-详解
    IO基础操作和常识
    四 软件架构风格、质量属性、Web架构设计
    linux命令 记录
    史上第三大收购案,博通以 610 亿美元收购 VMware
    php比特教务选排课系统的设计与实现毕业设计源码301826
  • 原文地址:https://blog.csdn.net/qq_41124528/article/details/140448940