深圳2021.03.04python面试总结

1.redis非事务型流水线

使用事务的其中一个好处就是底层的客户端会通过使用流水线来提高事务执行时的性能。使用非事务型流水线(non-transactional pipeline)同样可以获得相似的性能提升,并且可以让用户同时执行多个不同的命令。

1.1 redis事务

redis的事务是以特殊命令MULTI为开始,之后传入多个需要执行的命令,最后以EXEC为结束,开始执行.MULTI和EXEC也会消耗资源,并且可能会导致其他重要的命令被延迟执行。但也可以在不使用MULTI和EXEC的情况下,获得流水线带来的所有好处。

1.2 非事务型流水线

pipe = conn.pipeline()

在执行pipeline()时传入True作为参数,或者不传入任何参数,那么客户端将使用MULTI和EXEC包裹起用户要执行的所有命令。
如果传入False为参数,那么客户端同样会像执行事务那样收集用户要执行的所有命令,只是不再使用MULTI和EXEC包裹这些命令。
如果用户需要向Redis发送多个命令,并且对于这些命令来说,一个命令的执行结果并不会影响另一个命令的输入,而且这些命令也不需要以事务的方式来执行的话,那么我们可以通过向pipeline()方法传入False来进一步提升Redis的整体性能。

没有使用非事务型流水线代码:

def update_token(conn, token, user, item=None):
    timestamp = time.time()
    conn.hset('login:', token, user)
    conn.zadd('recent:', token, timestamp)
    
    if item:
        conn.zadd('viewed:' + token, item, timestamp)
        conn.zremrangebyrank('viewed:' + token, 0, -26)
        conn.zincrby('viewed:', item, -1)

使用非事务型流水线后:

def update_token_pipeline(conn, token, uesr, item=None)
    timestamp = time.time()
    pipe = conn.pipeline(False)
    pipe.hset('login:', token, user)
    pipe.zadd('recent:', token, timestamp)
    
    if itme:
        pipe.zadd('viewed:' + token, item, timestamp)
        pipe.zremrangebyrank('viewed:' + token, 0, -26)
        pipe.zincrby('viewed:', item, -1)
    pipe.execute()

2.mysql的回表与覆盖索引。

参考: https://www.jianshu.com/p/8991cbca3854

2.1 什么是回表查询?

这先要从InnoDB的索引实现说起,InnoDB有两大类索引:

  • 聚集索引(clustered index)
  • 普通索引(secondary index)

InnoDB聚集索引和普通索引有什么差异?

  • InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引

(1)如果表定义了PK,则PK就是聚集索引;
(2)如果表没有定义PK,则第一个not NULL unique列是聚集索引;
(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引;

画外音:所以PK查询非常快,直接定位行记录。

  • InnoDB普通索引的叶子节点存储主键值
    画外音:注意,不是存储行记录头指针,MyISAM的索引叶子节点存储记录指针。

所谓的回表查询即先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。

2.2 覆盖索引的定义:

如果一个索引包含(或覆盖)所有需要查询的字段的值,称为‘覆盖索引’,即只需扫描索引而无须回表
当发起一个索引覆盖查询时,在explain的extra列可以看到using index的信息

2.3 覆盖索引的优化及限制

覆盖索引是一种非常强大的工具,能大大提高查询性能,只需要读取索引而不需要读取数据,有以下优点
1、索引项通常比记录行数要小,所以MySQL访问更少的数据。
2、索引都按值的大小存储,查询只需要更少的I/O。
3、数据引擎能更好的缓存索引,比如MyISAM只缓存索引。
4、覆盖索引对InnoDB尤其有用,因为InnoDB使用聚集索引组织数据,如果二级索引包含查询所需的数据,就不再需要在聚集索引中查找了。

限制
1、覆盖索引也并不适用于任意的索引类型,索引必须存储列的值。
2、Hash和full-text索引不存储值,因此MySQL只能使用BTree。
3、不同的存储引擎实现覆盖索引都是不同的,并不是所有的存储引擎都支持覆盖索引。
4、如果要使用覆盖索引,一定要注意SELECT列表值取出需要的列,不可以SELECT * ,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。

3.进程、线程、协程的区别

3.1 进程

进程是系统资源分配的最小单位, 系统由一个个进程(程序)组成。一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。

  • 文本区域存储处理器执行的代码
  • 数据区域存储变量和进程执行期间使用的动态分配的内存;
  • 堆栈区域存储着活动过程调用的指令和本地变量。

因此进程的创建和销毁都是相对于系统资源,所以是一种比较昂贵的操作。 进程有三个状态:

  • 等待态:等待某个事件的完成;
  • 就绪态:等待系统分配处理器以便运行;
  • 运行态:占有处理器正在运行。

3.2 线程

  • 线程属于进程
  • 线程共享进程的内存地址空间
  • 线程几乎不占有系统资源 通信问题: 进程相当于一个容器,而线程而是运行在容器里面的,因此对于容器内的东西,线程是共同享有的,因此线程间的通信可以直接通过全局变量进行通信,但是由此带来的例如多个线程读写同一个地址变量的时候则将带来不可预期的后果,因此这时候引入了各种锁的作用,例如互斥锁等。
  • 同时多线程是不安全的,当一个线程崩溃了,会导致整个进程也崩溃了,即其他线程也挂了, 但多进程而不会,一个进程挂了,另一个进程依然照样运行。

3.2 协程

  • 协程是属于线程的。协程程序是在线程里面跑的,因此协程又称微线程和纤程等
  • 协程没有线程的上下文切换消耗。协程的调度切换是用户(程序员)手动切换的,因此更加灵活,因此又叫用户空间线程.
  • 原子操作性。由于协程是用户调度的,所以不会出现执行一半的代码片段被强制中断了,因此无需原子操作锁。

4.mq如何保证消息不丢失

4.1 消息丢失原因

在这里插入图片描述

4.2 解决方案

1.消息发送者发送给MQ Broker后,MQ Broker给生产者confirm确认收到
2.MQ收到消息进行消息持久化
3.消费者收到消息处理完毕后手动进行ack确认
4.MQ收到消费者ack确认后删除持久化的消息
在这里插入图片描述

5.mq如何保证消息不重复消费。

  • 消息重复原因: 网络不可达,不可避免。
  • 幂等性: 消息携带全局ID,消费方接到消息时先查再处理,根据全局ID做判重操作,已消费的不再消费。

6.如何保证分布式事务的数据一致性。

7.服务注册与发现如何实现。

8.悲观锁和乐观锁。

8.1 悲观锁(Pessimistic Lock)

1️⃣理解
当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式被称之为悲观并发控制【Pessimistic Concurrency Control,缩写“PCC”,又名“悲观锁”】。

传统的关系型数据库使用这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

2️⃣悲观锁主要分为共享锁和排他锁:

共享锁【shared locks】又称为读锁,简称S锁。顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
排他锁【exclusive locks】又称为写锁,简称X锁。顾名思义,排他锁就是不能与其他锁并存,如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据行读取和修改。

8.2 乐观锁(Optimistic Locking)

1️⃣理解
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场景,这样可以提高程序的吞吐量。

乐观锁机制采取了更加宽松的加锁机制。乐观锁是相对悲观锁而言,也是为了避免数据库幻读、业务处理时间过长等原因引起数据处理错误的一种机制,但乐观锁不会刻意使用数据库本身的锁机制,而是依据数据本身来保证数据的正确性。

2️⃣乐观锁的实现:
CAS 实现: CAS (Compare and Swap)。
CAS 即比较并交换。是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS 操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值(V)与预期原值(A)相匹配,那么处理器会自动将该位置值更新为新值(B)。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。CAS 有效地说明了“我认为位置(V)应该包含值(A)。如果包含该值,则将新值(B)放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可”。

版本号控制:一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会+1。当线程A要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。

9.迭代器和可迭代对象

9.1 可迭代对象:可以重复取值的对象,例如字符串、列表、字典、集合、元组、文件句柄、range方法等。

判断标准:方法中含有__iter__的对象。(可以用dir()查询对象含有的方法)

优点: 存储的数据能直接显示,比较直观

          拥有的方法较多,操作方便(这里是指点方法如 t1.upper)

缺点: 占用内存

          不能迭代取值(除索引、key以外)

9.2 迭代器:可以迭代取值的工具。

判断标准:内部含有__iter__和__next__方法的对象。迭代器实现了无参数的__next__方法,返回序列中的下一个元素,如果没有元素了,那么抛出StopIteration异常

迭代器如何取值:next(迭代器)

优点:节省内存,迭代器的原理是只占用一个数据的存储空间,每次取值的时候,上一条信息的空间会在内存中释放,只加载当前的数据。(有点像子弹的上膛,可迭代对象像是手枪的弹夹,迭代器像是手枪的枪膛)

         惰性机制:迭代器处理数据集的时候,会按需一次获取一个数据

缺点:速度慢(需要上子弹)

       取值的时候只能向下取值,不能取上一个值(没有回头箭)

10. 如何判断字典是否存在某个key

python2.2 has_key() 方法: if data_dict.has_key(‘name’):
python3 in关键字:if ‘name’ in data_dict:

11.判断对象类型

type(x) 或者isinstance(x, dict)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值