面试笔记(1)
该文章下的 mysql 题目取自网络,我是二次进行对应延伸的思考
1.Python 的 with 使用过吗,使用在哪些场景,原理是啥
with 相当于一个上下文管理器,主要用于打开资源或者关闭资源的场景,比如文件读写,数据库连接等,在执行出现异常的情况下,也能正常的关闭资源,相当于 try-finally 的二次封装嘛,主要调用了enter和exit两种魔术方法,能正常关闭也是因为exit方法优先级高,exit有三个参数异常类型,异常值,异常回溯,比起 try-finally 语句更加的优雅。
2.Python list 底部是内存是连续分布的吗
连续内存块存储的是引用,而不是真正的数据,真正的数据可能存放在内存的任意位置。因为比起 golang 或者 c++来说,我记得定义数组时候要定义数组的长度,而 python 没有就说明 python 底部存储真正的数据肯定不是连续分布的,预分配原则
3.说说 fastapi 依赖注入和装饰器有啥区别
fastapi 依赖注入允许你在路由函数和子依赖中声明所需的依赖,通过 depends 函数实现,依赖可以是函数或者类或者其他对象,装饰器的参数是一个函数,允许你在不修改源码的情况下去增添额外的功能,依赖注入可以通过函数签名显式传递,装饰器可能需要你从 request.header 去提取,依赖注入可以独立的进行测试,装饰器需要去嵌到路由里,整个去测试
4.知道哈希表吗
哈希表是一个通过哈希函数将 key 映射到数组的索引,哈希表底层就可以理解为一个数组,因为数组索引是唯一的,所以哈希表的 key 也得是唯一的,如果有太多的数据可能会发生哈希冲突,一般冲突的解决方式有两个,一个是链地址,就每个数组存储一个链表,然后这样一层一层的搭下去,一种是开放寻址法,就是横向扩展,如果有冲突就寻到旁边的位置。平均时间复杂度是 O(1),因为哈希函数直接计算出索引,在数组中通过索引寻值就是这样
5.你项目中有写到将数据报表缓存到 redis 中,如何 redis 中没有找到对应的数据呢
我是这样的,如果在 redis 里没有找到,会直接访问数据库拿数据去生成一个新的报表,然后通过 celery 异步任务去生成一份最新的去缓存到 redis 中
6.mysql 有哪些索引类型
1.主键索引,一种特殊的普通索引
2.唯一索引,保证索引列的值是唯一的,但是可以是空值
3.普通索引
4.全文索引,用于文本搜索的索引
5.复合索引,就是多个列共同组成索引,查询时候按照最左前缀原则进行查询,否则可能会索引失效
7.redis 数据类型
1.简单动态字符串
2.列表
3.集合
4.有序集合
5.哈希表
6.位图(bitmap)
7.地理空间位置
8.Stream
8.flask 和 fastapi 使用过吗,为啥会选用 fastapi
1.第一个肯定是因为 fastapi 的性能更高,原生就支持异步,flask 需要 gevent 第三方库,而且还不好用
2.fatsapi 支持 api 文档,flask 需要去进行第三方库比如 swagger
3.fastapi 支持类型注解,结合 pydantic 能简便处理相应数据,flask 需要手动去处理 request.json 数据
4.fastapi 支持依赖注入,flask 要用到装饰器
9.linux 命令
1.ls 命令(ls -a 全部列出)(ls - l 以列表模式列出)
2.cat,less (cat 查看小文件,less 查看大文件,带有分页)
3.cd 切换工作目录
4.touch 创建空白文件(touch -a 修改读取时间 touch - m 修改修改时间)
5.mkdir 创建文件夹
6.pwd 查看当前文件夹的工作目录
7.rm 删除文件命令
8.grep 在文件里寻找关键字
10.python 静态方法和类方法和类实例方法
类方法通过@classmethod 装饰器进行修饰,第一个参数是 cls,可以直接通过类去调用也可以实例化去调用,用于进行类级别数据的修改
类实例方法第一个参数为 self,可以修改实例的属性和方法
静态方法通过@staticmethod 装饰器进行修饰,不需要传递类对象和实例对象,直接进行类名进行调用
11.python 内存管理(垃圾回收)
python 的内存管理主要有三个机制:引用计数,标记清理,分代收集
1.python 对象是一个 pyobject,其中有一个 ref_count 的属性,通过计算这个对象有几处引用来决定这个对象需不需要回收
2.但是可能会出现循环引用的问题,python 里就使用了标记清理的方法,类似于图,底部是双向链表维护的,如果对象不可达,则说明这个可以回收他
3.但是遍历是很消耗性能的,则是将 Python 中的所有对象分为三代。刚刚创立的对象是第 0 代;经过一次垃圾回收后,依然存在的对象,便会依次从上一代挪到下一代。而每一代启动自动垃圾回收的阈值,则是可以单独指定的。当垃圾回收器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收。事实上,分代收集基于的思想是,新生的对象更有可能被垃圾回收,而存活更久的对象也有更高的概率继续存活。因此,通过这种做法,可以节约不少计算量,从而提高 Python 的性能
12.协程,线程,进程的区别
进程是操作系统分配资源的基本单位,最小的执行单元是内存,进程之间是相互隔离的,一个进程崩溃不影响另一个进程
线程属于进程,最小的执行单元是一个 cpu,多个线程共享进程的内存空间,进程和线程都是由操作系统进行调度
协程是一种轻量的线程,相当与线程中的并发,可以由我们来调度。python 的话可以使用 gevent 实现协程
13.异步和同步区别
同步是顺序执行的,前面任务没完成,后面任务就会被阻塞住
异步任务是并发执行的,是非阻塞的
14.docker 和 docker compose
docker 是一个容器化平台,容器基于镜像去运行,不受到底层操作系统的限制。docker compose 负责多个容器的配置,定义多个服务的依赖关系
15.k8s 和消息队列
k8s 是一个容器编排平台,负责自动化部署,运行,管理容器
核心概念
- pod: k8s 的最小调度单位,一个 pod 负责一个容器或者多个紧密相关的容器,比如 web 应用和日志收集器
- node: 集群中的物理或虚拟机,运行 Pod 的工作节点
- cluster: 一组 node 的集合
- deployment: 声明式管理 Pod 的资源
- service: 为 pod 提供稳定的 ip,dns 网络服务,实现负载均衡
- configmap: 存储配置数据
- secret: 存储敏感信息
- Volume: 数据卷,提供持久化存储
16.mysql 优化
- 建立合适的索引
- 分库分表
- 优化 sql 语句(比如只返回需要的列,将多次 insert 或 update 的操作改为批量写,读场景可以增大缓冲池大小,写缓冲可以更改写缓冲的策略)
17.redis 如何防止缓存雪崩
1.缓存穿透-访问的数据既不在缓存中也不在数据库中,导致每次都会穿透到数据库中,可以先缓存一个短期的空值或者加一个布隆过滤器,看看 key 是否存在
2.缓存击穿-指的是一个热点 key 过期,大量的请求去访问数据库,导致数据库宕机,可以给热点 key 设置永不过期然后异步更新缓存
3.缓存雪崩-指的是大量的 key 同时过期,导致大量的请求访问数据库,设置不同的过期时间,使用 redis 集群
18.redis 的持久化机制
1.通过 RDB,点对点快照,通过定期将数据存储在 rdb 文件里
2.AOF 机制,记录每条写操作的日志文件,通过重放恢复数据集
19.设计模式
- 1.单例模式:一个类确保有一个实例,其他对象共享这个实例,应用的话再数据库连接,日志的实例
- 2.装饰器模式:动态去增加功能,应用的话在鉴权这块
- 3.工厂模式:通过工厂类去隐藏实例化细节,应用的话就是可以动态接受参数
- 4.策略模式:定义一些可互换的算法,比如排序算法的替换
- 5.外观模式:为复杂子系统提供简单的操作,比如封装一套操纵数据库的接口
- 6.观察者模式
- 7.建造者模式
- 8.抽象工厂模式
- 9.适配器模式