1.列表常用方法 append:用于在列表末尾追加新的对象 extend:可以在列表末尾一次性追加另一个序列的多个值 count:用来统计某个元素在序列中出现的次数 index:用来查找某个值第一个匹配项的索引的位置 insert:用于将对象插入到列表中 pop:删除列表的一个元素,默认是最后一个,并且返回元素的值 remove:用于移除列表中某个值的第一个匹配项 reverse:将列表中的元素反向存放 sort:用于在原位置对列表进行排序,改变原来的列表,让其中的元素按一定顺序排列
2.字符串常用方法 find:可以在一个较长的字符串中查找子串,他返回子串所在位置的最左端索引 join:split的逆方法,用来连接两个字符串 split:将一个字符串分割成多个序列 strip:去除字符串中首尾的空格,并不包括字符串中间的空格 replace:替换,将字符串中某个匹配的子串替换为指定的子串
3.字典常用方法 clear:请求字典中所有元素,这是一个原地操作,所以,无返回值 fromkeys:使用给定的键建立新的字典,每个键都对应一个默认值None get:是个更宽松的访问字典项的方法,如果访问字典中不存在的项,只会返回None for遍历字典的三种方法: items:同时遍历字典的键和值 keys:遍历字典的键 values:遍历字典的值 pop:用于删除给定的键,然后在字典中移除键值 setdefault:在某种程度上类似于get方法,能够获得与给定键相关联的值,还能在字典中不含有给定键的情况下设定相应的值 update:可以利用一个字典项更新另一个字典,提供的字典中的项会被添加到旧的字典中,如有相同的键则会被覆盖
4.集合常用方法 intersection:交集,返回的两个序列中都拥有的元素 nuion:并集,返回两个序列所有的元素,且去重 difference:差集,返回该序列有而另一个序列没有的元素
5.进程 进程是资源分配的最小单位,当一个可执行程序被系统分配内存等资源执行时,就变成了一个进程 程序并不能单独运行,只有将程序装载到内存中,系统为他分配内存,才能运行,这种执行的程序旧称为进程 程序和进程的区别就在于,程序是指令的集合,它是进程运行的静态描述文本,进程是程序的一次执行活动,属于动态概念 在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下, 可以实现并发地执行 进程之间都有自己独立的内存,各进程之间不能相互访问 创建一个新线程很简单,创建新进程需要对父进程进行复制 多道编程:在计算机内存中同时存放几道相互独立的程序,他们共享系统资源,相互穿插运行 单道编程:计算机内存中只允许一个程序运行 提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率 进程间相互访问数据的四种方法: 利用Queues是新鲜进程间的数据传递 使用管道pipe实现两个进程间的数据传递 Managers实现多进程间的数据共享 利用redis中间件进行数据共享 进程和程序的区别:
程序只是一个普通文件,是一个机器代码指令和数据的集合,所以,程序是一个静态的实体而进程是程序运行在数据集上的动态过程,进程是一个动态实体,它应创建而产生,应调度执行因等待资源或事件而被处于等待状态,因完成任务而被撤消进程是系统进行资源分配和调度的一个独立单位 4.一个程序对应多个进程,一个进程为多个程序服务(两者之间是多对多的关系)一个程序执行在不同的数据集上就成为不同的进程,可以用进程控制块来唯一地标识每个进程6.线程 线程是操作系统调度的最小单位 它被包含在进程中,是进程实际的运作单位 进程本身是无法自己执行的,要操作CPU,必须创建一个线程,线程是一系列指令的集合 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行
进程线程的区别: 进程包含线程 线程共享内存空间 进程内存是独立的
守护线程SetDaemon:主线程退出时,需要子线程随主线程退出 GIL全局解释器锁:保证同一时间仅有一个线程对资源有操作权限,但是其他线程可以看见该资源
线程锁: 1)当一个线程对某个资源进行CPU计算的操作时加一个线程锁,只有当前线程计算完成主动释放锁,其他线程才能对其操作 2)这样就可以防止还未计算完成,释放GIL锁后其他线程对这个资源操作导致混乱问题
7.协程 协程,又称微线程,纤程,协程是一种用户态的轻量级线程 线程的切换会保存到CPU的栈里,协程拥有自己的寄存器上下文和栈 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈 协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态 协程最主要的作用是在单线程的条件下实现并发的效果,但实际上还是串行的(像yield一样) 协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上线程阻塞(Blocking)操作(如IO时)会阻塞掉整个程序 协程为何能处理大并发:Greenlet遇到I/O手动切换
协程之所以快是因为遇到I/O操作就切换(最后只有CPU运算)其实Gevent模块仅仅是对greenlet的再封装,将I/O间的手动切换变成自动切换协程为何能处理大并发:Gevent遇到I/O自动切换
Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。Gevent原理是只要遇到I/O操作就会自动切换到下一个协程9.装饰器 不修改原函数,不修改原函数的调用方式,为其他函数添加其他功能 使用场景: 授权:装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。它们被大量使用于Flask和Django web框架中 日志:在记录日志的地方添加装饰器 缓存:通过装饰器获取缓存中的值
10.生成器 生成器可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他数据类型需要调用自己的内置iter方法) 在Python中,一边循环,一边计算的机制,称为生成器。
通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的 而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 所以,如果列表元素可以按照某种算法推算出来,就不必创建完整的list,从而节省大量的空间。
11.迭代器 迭代器是访问集合内元素的方式,迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束 代器仅是一容器对象,它有两个基本方法 1)next方法:返回容器的下一个元素 2)__iter__方法:返回迭代器自身
生成器和迭代器之间的区别 在使用生成器时,我们创建一个函数;在使用迭代器时,我们使用内置函数iter()和next()。 在生成器中,我们使用关键字‘yield’来每次生成/返回一个对象。 生成器中有多少‘yield’语句,你可以自定义。 每次‘yield’暂停循环时,生成器会保存本地变量的状态。 而迭代器并不会使用局部变量,它只需要一个可迭代对象进行迭代。 使用类可以实现你自己的迭代器,但无法实现生成器。 生成器运行速度快,语法简洁,更简单。 迭代器更能节约内存。
12.静态方法、类方法、属性方法、魔法方法 静态方法: 静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,主要是一些逻辑属于类,但是和类本身没有交互,即在静态方法中,不会涉及到类中的方法和属性的操作。 可以理解为将静态方法存在此类的空间中。事实上,在python引入静态方法之前,通常是在全局名称空间中创建函数。 既可以被类直接调用,也可以通过实例调用 类方法: 无需实例化直接被类调用,类方法直能访问类变量,不能访问实例变量 既可以被类直接调用,也可以通过实例调用 属性方法: 把一个方法变成了一个属性,隐藏了实现细节,调用时不必加括号直接调用即可 魔法方法: new:先于init方法,是用来创建实例对象的 init:初始化实例对象的 call:实现了这个魔法方法的类对象可以当函数调用 del:删除无用的内存对象(当程序结束会自动执行)
13.深浅拷贝 浅拷贝 只拷贝顶层数据,其余数据拷贝时是引用关系
递归性质的拷贝,所有数据完全拷贝。数据之间彼此独立,互不影响
14.python垃圾回收机制 当一个数据被变量引用时,引用计数加1 当变量被删除时,引用计数减1 当引用计数为0时,对应的数据真正的从内存中删除 标记清除:分为两个阶段,第一个阶段是标记,将所有的活动对象打上标记,第二个阶段是把没有标记的非活动对象进行回收
15.上下文管理 with是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和资源分配释放相关代码统统去掉,简化try….except….finlally的处理流程 所以使用with处理的对象必须有enter和exit方法 with通过enter方法初始化,然后在exit方法中做善后及异常处理 with适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源 比如文件使用后自动关闭,线程锁的自动获取和释放
16.四大高阶函数 lambda:又称为匿名函数,或者函数表达式 它拥有函数的功能,但是它只是一个表达式,不是一个代码块,所以,仅仅能封装有限的逻辑进去
三元运算符: 又称为三目运算,主要作用是减少代码量,是对简单的条件语句进行缩写 格式为:值1 if 表达式 else 值2 如果表达式为真,则取值1,如果表达式为假,则取值2
filter:可以对序列做过滤处理 map:将可迭代对象中的每个元素,按照函数进行逐一操作,得到一个结果为迭代器对象 reduce:即为化简函数,每一次迭代,都将上一次的迭代结果与下一个元素一同传入二元func函数中去执行 将可迭代对象中的数据按照函数连续操作得到一个具体的值 sorted:排序
17.mysql事务 事务(Transaction)是数据库区别于文件系统的重要特性之一,事务会把数据库从一种一致性状态转换为另一种一致性状态。 2. 在数据库提交时,可以确保要么所有修改都已保存,要么所有修改都不保存。
原子性:事务包含的所有操作要么都执行成功,要么都失败,不可分割 一致性:中间过程不管怎么执行,结果一定是一致的 隔离性:事务在执行过程中,不受其他事务的影响 持久性:执行成功之后,结果时永久修改的,不能撤回18.mysql中的锁 按操作划分:DML锁,DDL锁 按锁的粒度划分:表级锁,行级锁,页级锁 按锁级别划分:共享锁,排他锁 按加锁的方式划分:自动锁,显示锁 按使用方式划分:乐观锁,悲观锁
什么是乐观锁: 比如每次获取商品时,不对该商品加锁 在更新数据的时候需要比较程序中的库存量与数据库中的库存量是否相等,如果相等则进行更新 如果不等,那么就会重新获取数据,再次进行比较,直到两个库存量的数值相等才更新数据 什么是悲观锁: 每次获取商品时,对该商品加排他锁。 也就是在用户A获取获取 id=1 的商品信息时对该行记录加锁,期间其他用户阻塞等待访问该记录
什么是排它锁: 排他锁又叫写锁,如果事务T对A加上排他锁,则其他事务都不能对A加任何类型的锁 获得了排他锁的事务既能读数据,又能写数据
什么是共享锁: 共享锁又叫读锁,如果事务T对A加上共享锁,则其他事务只能对A再加共享锁,不能加其他锁 获得了共享锁的事务只能读,不能写
19.mysql优化
1.字段设计优化:适应遵循数据库三大范式2.引擎的选择:适应选择MyIsam或者InnoDB3.索引:索引也会消耗内存空间,不是越多越好4.查询缓存:将select查询结果缓存起来,key为SQL语句,value为查询结果5.分区6.水平分割和垂直分割7.集群8.SQL语句9.服务器的选择为什么要mysql优化: 系统的吞吐量瓶颈往往出现在数据库的访问速度上,数据越来越多,速度会越来越慢
20.B-tree/B+tree
B-tree是根据数据结构中的二叉树进化而来,每个节点占用一块磁盘空间,一个节点上有两个升序排序的关键字和三个指针(指向下一层的子节点),指针存储的是子节点所在磁盘的地址 以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。 可以对数据进行快速的查找 由于磁盘是转动的,每转动一圈的时候,停留在一个节点上,为了将这个节点完全的读取到,利用了B-tree的原理
B+Tree的非叶子节点只存储键值信息 简单来说,B+tree有两个指针,一个指向了根节点,一个指向关键字最小的叶子节点 所有的叶子节点之间,是一个链试环结构
B+tree相对于B-tree查找更加精确,但是,需要牺牲掉一部分性能和存储空间 B-tree是单向的,B+tree是有反向查找机制的,所以是要存储上一个父节点的,所以,在空间上会有一定的占有
21.mysql主从同步原理 1.master(主)服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中; 2.slave(从)服务器会在一定时间间隔内对master二进制日志进行探测是否发生改变,如果发生改变,则开始I/OThread请求master二进制事件 3.同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志中读取二进制日志 在本地重放,使得其数据和主节点的保持一致,最后I/OThread和SQLThread将进入睡眠状态,等待下一次被唤醒。
22.mysql-慢查询应用 慢查询就是记录查询缓慢语句的日志
记录查询缓慢的sql语句,方便mysql查询性能优化,为优化提供精准的定位 简单来说,遇到一个查询缓慢的sql语句,数据库的管理员也就是DBA 会找查询慢的原因,优化sql语句,将优化好的语句交给程序员,让程序员来替换掉原来的sql语句
查看慢查询是否开启: show variables like ‘slow_query%’; 开启mysql慢查询监控:1是开启,0是关闭 set global show_query_log = 1 查看默认慢查询阈(yu)值的时间: show variables like ‘long_query’ 设置默认慢查询阈(yu)值时间:按秒算 set long_query_time = 1
23.mysql-主丛一致校验 可以通过采用pt-table-checksum工具来检查主从的一致性
24.mysql-基于Docker的主从复制
一台服务器可以运行多个docker容器。 docker 容器之间相互独立,互不冲突。 docker 使用步骤简便。
主从复制指的是一台服务器充当主服务器,另一台或多台服务器充当从服务器 主服务器的数据自动复制到从服务器中 对于多级复制,数据库服务器即可充当主机,也可以充当从机
为什么要使用主从复制: 1)实现服务器负载的均衡,主服务器负责写入,更新,删除,由于每次操作都会同步到从服务器上 从服务器就可以负责压力比较大的查询工作了 2)提交数据库系统的可用性,由于两台服务器的数据是一致的,那么主服务器一旦发生宕机,从服务器就可以临时担任主服务器的工作 3)数据库备份 主从复制的模式: SBR:只记录增删改的日志,同步到另外一台服务器上,由服务器通过日志的变化来产生数据 RBR:不光同步数据,连数据库中的存储过程函数等,会使日志暴涨,导致数据库硬盘空间爆满 MBR:这个模式综合了以上两种模式的优点和缺点,会在两种模式下相互切换
25.redis的五大数据类型实现原理 redis中所有的数据结构都以唯一的key字符串作为键(名称),然后通过这个唯一的key来获取对应的value 不同的数据类型数据结构差异就在于value的结构不一样 字符串,value的数据结构类似于数组,string类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象,使用场景:缓存 列表,value的数据结构类似于双向链表,这意味着插入和删除的时间复杂度是O(1),索引的时间复杂度为O(n),场景:队列和栈 hash:数据结构为HashMap(数组+列表)的二维结构,类似字典,不同的是,redis的字典的值只能是字符串 集合:集合是string类型的无需集合,是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1) 有序集合:和集合类似,但它是有序的,且不允许重复
26.redis事务 redis的事务是可以一次执行多个命令,本质是一组命令的集合 一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入 他的作用是,一个队列中,一次性、顺序性、排他性的执行一系列命令 redis原子操作 原子操作是指不会被线程调度机制打断的操作 这种操作一旦开始,就会一直运行到结束,中间不会切换任何进程
27.redis分布式锁 分布式锁本质是占一个坑,当别的进程也要来占坑时发现已经被占,就会放弃或者稍后重试 一般使用setnx(set if not exists)指令,只允许一个客户端占坑 使用完成后,调用del指令释放 但是这样有一个问题,如果逻辑执行到中间出现异常,可能导致del指令没有被调用,这样就会陷入死锁,锁永远无法释放 为了解决死锁问题,我们拿到锁时可以加上一个expire过期时间,这样即使出现异常,当到达过期时间也会自动释放锁
28.布隆过滤器 特点是,高效的插入和查询,相比于传统的List,Set,Map等数据结构,它更加的高效,占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的 如果用户来查询一个row时,可以先通过布隆过滤器过滤掉大量不存在的row请求,然后再去磁盘进行查询 布隆过滤器说某个值不存在时,那肯定就是不存在,可以显著降低IO请求数量
28.5 redis持久化 RDB(全量):把redis数据库中的数据全部重新写入到磁盘中 AOF(增量):把修改,添加,删除这些记录每一个都记录到日志中
29.redis学崩&穿透&击穿 击穿: 一个请求到达服务器,优先从缓存中获取数据,如果数据没有命中(查找到) 那么这个请求就会去数据库查找,请求量过于庞大的时候,对数据库就是如雷灌顶 简单来说,击穿就相当于缓存墙被打破,大量请求涌入数据库导致数据库崩塌 穿透: 和击穿类似,但不同的是,缓存中没有数据,它去请求数据库,数据库中也没有数据,查询结果为空 一般情况下,是无用的请求导致的redis穿透 雪崩: 当缓存中的热点数据在同一时间失效,造成大量的请求涌入数据库,造成大量击穿,导致服务器瘫痪
30.主从同步 CPA原理是分布式存储理论的基石: C(一致性); A(可用性); P(分区容忍性); 主从刚刚连接的时候,进行全量同步,全量同步结束后,进行增量同步
31.哨兵模式 redis做主从方案时,redis无法自动进行主备切换,这时,就需要用到哨兵模式 哨兵模式是一个特殊的模式,他是一个独立的进程 监测redis服务器响应,如果发现主服务器宕机,他会让一个从服务器暂时充当主机 原理: 持续监控redis主节点的正常否,如果主节点发生故障,会自动选择一个最优的从节点替换成主节点 从节点来连接集群时,首先连接的是哨兵,通过哨兵来查询主节点的地址 主节点故障时,哨兵会将最新的主节点地址告诉客户端,无需重启自动切换redis
32.codis集群 在大数据高并发场景下,单个redis实例往往会无法应对 首先redis内存不易过大,内存太大会导致rdb文件过大,导致主从同步时间过长
什么是codis: codis是redis集群解决方案之一,它是GO语言开发的代理中间件 哨兵模式解决的是处理数据的速度,依旧储存不了更多的数据 codis解决了这个问题,所有redis中的数据是不一样的,通过查询的key,把key转换成整数,指定存放位置,查找同理
33.常见数据结构 栈:栈是一种数据集合,可以理解为只能在一端进行插入或删除操作的列表 队列:队列是一个数据集合,仅允许在列表的一端进行插入,另一端进行删除 链表:链表的每个元素都是一个对象,每个对象都称为节点,包含了数据和指向下一节点的指针,由此结构串联成的数据结构就是链表 数组:所谓数组,就是相同数据类型的元素按一定顺序排列的集合,类似列表,但是,只能放相同的元素
34.二分法查找 二分法查找的前提是,序列必须是有序的
35.冒泡法排序 拿自己与上面一个比较,如果上面一个比自己小就将自己和上面一个调换位置 依次再与上面一个比较,第一轮结束后最上面那个一定是最大的数 def f1(list1): n = len(list1) for i in range(n-1): for j in range(n-i-1): if list1[j]>list1[j+1]: list1[j],list1[j+1]=list1[j+1],list1[j]