面试
1.面向对象
三大特性:封装,继承,多态
封装:
函数,属性,同一类的要封装到一起,字段封装到对象里。
应用:自定义分页(当前页有多少数据,有多少页,只需要起始和结束页传进来),drf源码中请求进来,将原来的request和认证的所有对象封装到一起
as_view() --> view() --> dispatch() --> initialize_request()对request进行封装
继承:
drf中视图继承APIView,modelForm中继承django的form.ModelForm,ModelForm又继承了BaseForm,有时候需要加BootStrap的样式自己会写一个类重写init方法,然后让form类继承这个类
drf中view --> APIView --> GenericAPIView --> ListModelMixin --> ListAPIView --> UserInfoView
GenericAPIView中定义了serilizer_class等规则,在视图类中重写。
多态:
比如对于一个arg.send()方法,不管实例化的是哪个对象只要有这个方法就能执行
class XX():
def send():
pass
class Email():
def send():
pass
class Msg():
def send():
pass
def func(arg):
arg.send()
obj = Email()
func(obj)
2.Django生命周期
WSGI是一个协议
wsgiref是实现了wsgi协议的一个模块,本质是一个socket服务端。
werkzeug是实现了wsgi协议的一个模块,本质是一个socket服务端。(flask)
uwsgi是实现了wsgi协议的一个模块,本质是一个socket服务端。性能更好
tornado,自己实现的socket
请求进来后经过路由匹配,到类.as_view(),as_view()中返回了一个View函数,view函数中执行了dispatch,然后是请求的封装,认证,权限,限流
中间件和装饰器:
1、process_request : 请求进来时,权限认证 。
2、process_view : 路由匹配之后,能够得到视图函数
3、process_exception : 异常时执行
4、process_template_responseprocess : 模板渲染时执行
5、process_response : 请求有响应时执行
中间件:适用于对所有请求做批量操作,rbac基于用户的权限控制,用户登录,csrf_token,session,黑名单,日志记录
csrf_token:返回用户时携带一个随机的字符串,请求时再携带上这个字符串
session:process_request时给用户一个session,用户拿到后赋值,在process_response 时写入到数据库
黑名单:拿到用户的IP,限制用户
日志记录:记录所有用户的请求
rest框架:
a.认证流程
记不太清,两个方法authenticate,authenticate_header
返回3个,(异常,None,元组–>赋值给request)
b.权限
返回True/False
has_permission
c.节流(IP,代理,用户名)
返回True/False
用户唯一标识当作key,放到缓存,访问记录是一个列表,每次请求过来把最远的时间剔除掉根据个数判断是否在一个范围内
d.序列化
数据校验和将数据序列化返回给用户
序列化步骤:
request.body和request.POST:
同时满足contenType里面是application/x-www-form-urlencoded,数据格式时a=123&b=123,否则POST没值,body有值,
3.GIL及多线程
线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.对于io密集型任务,python的多线程起到作用,但对于cpu密集型任务,python的多线程几乎占不到任何优势,还有可能因为争夺资源而变慢。
对于IO密集型任务例如磁盘读写与网络请求就用多线程
对于计算密集型任务就使用多进程 mutliprocess模块
from multiprocessing import Pool
import os,time,random
def worker(msg):
t_start = time.time()
print("%s开始执行,进程号为%d"%(msg,os.getpid()))
#random.random()随机生成0~1之间的浮点数
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执行完毕,耗时%0.2f"%(t_stop-t_start))
po=Pool(3) #定义一个进程池,最大进程数3
for i in range(0,10):
#Pool.apply_async(要调用的目标,(传递给目标的参数元祖,))
#每次循环将会用空闲出来的子进程去调用目标
po.apply_async(worker,(i,))
print("----start----")
po.close() #关闭进程池,关闭后po不再接收新的请求
po.join() #等待po中所有子进程执行完成,必须放在close语句之后
print("-----end-----")
在网上查多线程资料的时候,很多文章讲到了对Python的多线程与多进程的理解,包括相同之处和它们之间的区别,我就整理了一些点放在这里:
**进程ID:**多线程的主进程和它的子线程的进程ID,即os.getpid(),都是相同的,都是主进程的进程ID。多进程则是主进程和它的子进程都有各自的进程ID,都不相同。
**共享数据:**多线程可以共享主进程内的数据,但是多进程用的都是各自的数据,无法共享。
**主线程:**由Python解释器运行主py时,也就是开启了一个Python进程,而这个py是这个进程内的一个线程,不过不同于其他线程,它是主线程,同时这个进程内还有其他的比如垃圾回收等解释器级别的线程,所以进程就等于主线程这种理解是有误的。
**CPU多核利用:**Python解释器的线程只能在CPU单核上运行,开销小,但是这也是缺点,因为没有利用CPU多核的特点。Python的多进程是可以利用多个CPU核心的,但也有其他语言的多线程是可以利用多核的。
**单核与多核:**一个CPU的主要作用是用来做计算的,多个CPU核心如果都用来做计算,那么效率肯定会提高很多,但是对于IO来说,多个CPU核心也没有太大用处,因为没有输入,后面的动作也无法执行。所以如果一个程序是计算密集型的,那么就该利用多核的优势(比如使用Python的多进程),如果是IO密集型的,那么使用单核的多线程就完全够了。
**线程或进程间的切换:**线程间的切换是要快于进程间的切换的。
**死锁:**指的是两个或两个以上的线程或进程在请求锁的时候形成了互相等待阻塞的情况,导致这些线程或进程无法继续执行下去,这时候称系统处于死锁状态或者系统产生了死锁,这些线程或进程就称为死锁线程或死锁进程。解决死锁的办法可以使用递归锁,即threading.RLock,然后线程或进程就可以随意请求和释放锁了,而不用担心别的线程或进程也在请求锁而产生死锁的情况。
**信号量与进程池:**进程池Pool(n)只能是“池”中的n个进程运行,不能有新的进程,信号量只要保证最大线程数就行,而不是只有这几个线程,旧的线程运行结束,就可以继续来新的线程。
4.装饰器和闭包,迭代器,yield
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包
def foo():
a = 1
def bar():
nonlocal a
a = a + 1
return a
return bar
c = foo()
print(c()) # 2
让其他函数或类在不需要做任何代码修改的前提下增加额外功能(设计模式中的装饰器模式)
def my_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "info":
print("{} is running. level: ".format(func.__name__), level)
elif level == "warn":
print("{} is running. level: ".format(func.__name__), level)
return func(*args, **kwargs)
return wrapper
return decorator
@my_logging(level="info")
def foo(name="foo"):
print("{} is running".format(name))
@my_logging(level="warn")
def bar(name="bar"):
print("{} is running".format(name))
foo()
bar()
#foo is running. level: info
#foo is running
#bar is running. level: warn
#bar is running
上面的 my_logging 是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当使用@my_logging(level=“info”)调用的时候,Python 能够发现这一层的封装,并把参数传递到装饰器的环境中。
可见通过iter方法后就是迭代器。 它是一个带状态的对象,调用next方法的时候返回容器中的下一个值,可以说任何实现了__iter__和next方法的对象都是迭代器,__iter__返回迭代器自身,next返回容器中的下一个值,如果容器中没有更多元素了,则抛异常。 迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。
https://juejin.cn/post/6844903810205220878
-
武sir:
应用场景:classmethod(类方法,改变类变量cls.),staticmethod(无需实例化,不用self传参,直接通过类名.方法使用),
property(伪装成类的一个属性,直接.出来)
csrf,模板中自定义inclusion_tag,flask的route
5.事务
1.原子性 (Atomicity):就是事物的所包含的所有操作,要么全部成功,要么全部失败回滚。
2.一致性 (Consistency):简单来说就是在事物执行前和执行后,必须保持数据的一致。 举个例子:A和B之间进行转账,A和B的钱加起来一种是2000块钱,那么无论他们之间进行了多少次的转账操作,最后的钱数加起来应该还是等于2000。
3.隔离性 (Isolation):一个事物执行的过程当中,不能被其他的事物干扰。比如有事物A和事物B,相对于A来说,你B想要执行,要么在我执行之前执行,要么在我执行完毕之后,你再开始执行。
- 持久性 (Durability):事物被提交之后,他就被永久的存储到了数据库当中。
6.redis持久化
7.mysql高并发()
MySQL数据库如何使用sql语句插入一条数据
insert into [表名](PUNCHID,PERSONID,PUNCHDT,DEVICENUM) value 392140,581,'2016-08-01 19:11:00.000','2'
MySQL数据库如何进行查询优化
增加索引,优化数据库分解字段过多的表,
Mysql慢查询
查询超过2秒的查询
如何很多请求同时对Redis的同一个键进行访问,如何保证数据安全
原子操作
当数据越来越多,如何避免hash槽中key出现相同的情况?
业务隔离,不同场景使用不同的key命名格式
8.git多人
-
拉取远程分支
git init git remote add origin https地址 git fetch origin dev(dev为远程仓库的分支名) git checkout -b dev(本地分支名称) origin/dev(远程分支名称) git pull origin dev(远程分支名称)
-
回退版本
git reflog 获取所有提交的版本号 git reset –hard 版本号
9.tornado,django,flask区别
10.restful规范
一种风格,与技术无关所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
https://www.cnblogs.com/wupeiqi/articles/7805382.html
https,域名带api,版本,使用名词,5种方法,过滤条件(limit,offset,page,sortby),状态码,返回错误信息,结果中提供链接
11.正则
url('^/(?P<pk>\d+)/$',views.fuck),
12.跨域
由于浏览器具有同源策略的限制,在发送ajax请求时,如果当前浏览器的url是a.com,页面中向b.com发送ajax请求,请求可以正常,但数据回到浏览器时会被阻止。
-
解决跨域
在b.com中设置一个响应头就可以解决问题。 在中间件的process_response中将返回的数据添加: result['Access-Control-Allow-Origin'] = '*' return result
注意:项目上线之后,使用cors解决跨域,在Nginx上设置响应头
如果是非get,post的复杂请求,会先向服务器进行option请求进行预检。
13.堆栈
栈:先进后出,网站浏览顺序后退
队列:先进先出,排队
双端队列:回文 madam toot
14.django websocket
websocket
web,写网站让浏览器和服务端进行交互
socket,让网络上的两端创建链接并进行收发数据
http和https是无状态短链接
websocket是一个网络协议(让浏览器和服务端创建链接支持,默认不再断开,两端就可以完成相互之间的数据收发)
websocket实现原理:
- 握手环节,验证服务端是否支持websocket协议。
浏览器生成一个随机字符串,将随机字符串发送给服务端。
服务端接收到随机字符串后,让他跟magic string拼接,然后再进行sha1 / base64加密
将密文返回给用户浏览器
用户浏览器自动会进行校验
- 收发数据,密文
数据解密时需要读取数据第二个字节的后7位,如果
127
126
<=125
有不同的结果
django中使用websocket:
pip install channels==2.3
建议在3.6的环境中运行
在channels的内部已经帮助我们写了握手/加密/解密等所有环节。
tornado默认支持
flask使用geventwebsocket
https://www.cnblogs.com/wupeiqi/articles/9593858.html
有两种方式实现,其中是Django2.2结合channels,channel-redis实现,在setting.py中手动设置Asgi_application的路径,然后在视图中继承channels的websocketConsumer类,重写里面的connet,disconnet,receive方法,前端先new一个websocket对象,然后验证服务端是否支持websocket协议,浏览器会生成一个随机字符串,自己保留一份,给服务端发一份,服务端与全球公认的magic string拼接然后加密返回给浏览器,浏览器如果验证成功则连接成功。客户端发消息的话也是密文,数据解密时会读取数据包第二个字节的后七位,如果时127则往后读8个字节作为数据包头,如果是126则往后读两个字节作为数据包头,小于等于125则后面全部为数据,拿到数据后群发给前端
另一种实现方式是Django3.0像Tornado一样原生支持了异步,所以在项目asgi.py文件中,重写异步application方法,判断当前的请求类型是http还是websocket,如果是websocket就走自己定义的逻辑,先判断是否连接上,然后通过jwt获取用户,并在其他用户界面上显示出当前用户,如果是用户发送消息,则先拿到用户的消息然后通过websocket.send类型将消息返回给其他前端。
15.数据库原声语句(inner join 和 join 区别,满查询)
16.tcp/ip & Https
-
什么是http协议
超文本传输协议 基于TCP协议之上创建一个协议,此协议是无状态的短连接,Http可以通过两方面去解释 -短连接,一次请求一次响应之后断开连接。 -数据传输格式,请求头和请求体之间通过两个\r\n\r\n分隔,请求头和请求头之间通过一个\r\n分隔 浏览器输入Url:www.baidu.com/index/ 默认:80端口;明文传输。
-
什么是Https?
对传输的数据进行了加密 默认:443端口
- 对称加密,双方密钥相同。
- 非对称加密,公钥(加密)和私钥(解密)。
17.index索引为什么快
DB在执行一条Sql语句的时候,默认的方式是根据搜索条件进行全表扫描,遇到匹配条件的就加入搜索结果集合。如果我们对某一字段增加索引,查询时就会先去索引列表中一次定位到特定值的行数,大大减少遍历匹配的行数,所以能明显增加查询的速度。
18.进程线程协程
进程:计算机中资源分配的最小单元。
线程:计算机中CPU调度的最小单位。
协程:又称为‘微线程’,在计算机中不真实存在,而是程序员通过代码伪造出来的
一个进程中可以有多个线程,一个线程中又可以创建多个协程,在Cpython中还有一个GIL,全局解释器锁(同一时刻一个进程中只有一个线程可以被cpu调度),由于GIL的存在,导致Python中:计算密集型使用进程,IO密集型使用线程(协程)
19.redis数据结构使用场景及内存满了怎么办,挂了怎么办
https://www.cnblogs.com/pyyu/p/9843950.html
保存在内存,速度快,减轻I/O操作
默认端口:6379
strings list set 有序集合 哈希数据结构
redis一共有16384个哈希槽
redis.conf文件夹下更改databases 16 来改变redis想要的个数,修改requirepass 123456修改密码
当aof文件过大时用脚本执行BGREWRITEAOF对AOF重写,合并重复命令
-
redis持久化
rdb:基于快照的持久化,速度更快,一般用作备份,主从复制也是依赖于rdb持久化功能
aof:以追加的方式记录redis操作日志的文件。可以最大程度的保证redis数据安全,类似于mysql的binlog
-
内存满了怎么办
内存淘汰策略,内存淘汰策略相当于清除掉那些占用内存并且使用不太频繁的数据,淘汰掉这些不活跃数据来清理内存,
LRU算法,
least RecentlyUsed,最近最少使用算法。也就是说默认删除最近最少使用的键。
但是一定要注意一点!redis中并不会准确的删除所有键中最近最少使用的键,而是随机抽取5个键,删除这五个键中最近最少使用的键。
-
什么redis快
-
Redis是纯内存数据库,一般都是简单的存取操作,线程占用的时间很多,时间的花费主要集中在IO上,所以读取速度快。
-
再说一下IO,Redis使用的是非阻塞IO,IO多路复用,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。
-
Redis采用了单线程的模型,保证了每个操作的原子性,也减少了线程的上下文切换和竞争。
-
另外,数据结构也帮了不少忙,Redis全程使用hash结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。
-
还有一点,Redis采用自己实现的事件分离器,效率比较高,内部采用非阻塞的执行方式,吞吐能力比较大。
-
20.nginx负载均衡
平衡服务器集群压力,用户请求过来先到nginx,看看是不是静态资源,通过manage.py collectstatic,静态资源直接返回给浏览器,动态资源转交给uwsgi,uwsgi找到对应的django应用进行逻辑处理后将返回值通过uwsgi和nginx返回给用户浏览器。
21.B+ B树的区别
B+树
1、B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
3、B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。
B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。
index索引之所以快是因为正常检索一条数据要先遍历双向链表定位所在的页,如果不是主键查询那就需要遍历单链表,查询慢,
通过B+树的节点就可以快速定位到数据所在的页
22.关系型数据库和非关系型数据库的区别
关系型数据库:指采用了关系模型来组织数据的数据库。
非关系型数据库:指非关系型的,分布式的,且一般不保证遵循ACID
原则的数据存储系统
- 关系型与非关系型数据库的比较
1.成本:Nosql
数据库简单易部署,基本都是开源软件,不需要像使用Oracle
那样花费大量成本购买使用,相比关系型数据库价格便宜。
2.查询速度:Nosql
数据库将数据存储于缓存之中,而且不需要经过SQL
层的解析,关系型数据库将数据存储在硬盘中,自然查询速度远不及Nosql
数据库。
3.存储数据的格式:Nosql
的存储格式是key,value
形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。
4.扩展性:关系型数据库有类似join这样的多表查询机制的限制导致扩展很艰难。Nosql
基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
5.持久存储:Nosql
不使用于持久存储,海量数据的持久存储,还是需要关系型数据库
6.数据一致性:非关系型数据库一般强调的是数据最终一致性,不像关系型数据库一样强调数据的强一致性,从非关系型数据库中读到的有可能还是处于一个中间态的数据,
Nosql
不提供对事务的处理。
23.单例模式
import threading
import time
class Singleton(object):
instance = None #静态字段,类变量
lock = threading.RLock()
def __init__(self):
"""
初始化对象
"""
self.name = name
def __new__(cls,*args,**kwargs):
"""
创建对象
"""
if cls.instance:
return cls.instance
with cls.lock:
if not cls.instance:
time.sleep(0.2)
cls.instance = object.__new__(cls)
return cls.instance
obj1 = Singleton('alex')
obj2 = Singleton('sb')
print(obj1,obj2) #返回相同的内存地址
- 最方便的导入方法
模块的导入只能生效一次. 再重复导入只要基于一套环境都是使用的 最初 的那份资源.
(在被导入的模块文件中一定要先实例化对象,然后再其他的文件中导入已经实例化的对象)
24.http请求头
content-type:标记请求格式,json或&url拼接
user-agent
connection:keep-alive,保持长连接
host
25.反射(自省)及应用场景
根据字符串的形式操作对象中的属性(成员)。
应用场景:
django中间件的处理
process_request(self,request)
process_response(self, request, response)
process_view(self, request, view_func, view_args, view_kwargs)
process_exception(self, request, exception)
process_template_response(self,request,response)
https://www.jianshu.com/p/0e2fb8383661?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
cache 缓存中间件
Gzip 内容压缩中间件
Message 消息中间件 cookie
Session 会话中间件
csrf 提供csrf防御机制机制,只在POST时校验
#2.2中官方写法
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# 配置和初始化
def __call__(self, request):
# 在这里编写视图和后面的中间件被调用之前需要执行的代码
# 这里其实就是旧的process_request()方法的代码
response = self.get_response(request)
# 在这里编写视图调用后需要执行的代码
# 这里其实就是旧的process_response()方法的代码
return response
中间件可以用于拦截IP,校验token,当程序上线后debug设置为False,利用process_exception中间件,报错后管理员可以看到报错详细页面,普通用户看到500页面
26.什么是DRF:
本质是一个DJnago的组件,要在app中注册,
可以快速开发遵循restful规范的接口。
-csrf
-页面渲染(json放到页面了)
27.内存管理机制和垃圾管理机制
内存管理机制:
在Python中维护了一个refchain的双向环状链表,这个链表中存储程序创建的所有对象,每种类型的对象中都有一个obj_refcnt引用计数器的值,引用器+1或-1,最后当引用计数器变为0的时候会进行垃圾回收(对象销毁,refchain中移除)
但是,在Python中对于那些可以有多个元素组成的对象可能会存在循环引用的问题,为了解决这个问题python又引入了标记清除和分代回收,在其内部维护了4个链表。。
refchain 2代 1代 0代
在源码内部当达到各自的阈值时,就会触发扫描链表进行标记清除的动作(有循环各自-1)
垃圾回收机制
引用计数器为主,标记清除和分代回收为辅
28.查询加速
当all()拿到所有数据时需要外键的信息,使用select_related('外键名'),外键的外键-》select_related('外键名__外键名')
defer和only查询
29.tcp三次握手
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
https://www.cnblogs.com/bj-mr-li/p/11106390.html
30.celery相关
celery基本原理:
1、客户端也就是python(django/flask等)发布任务
2、发布的任务存到任务队列里面,可以以redis、rabbitMQ、MessageQueue、MySQL存储,一般在django/flask程序里redis居多
3、任务处理者会不断从任务队列里面获取任务执行
下单超时取消支付,超时自动收货,拍场定时开放定时关闭
31.一行写出乘法表
print('\n'.join(['\t'.join([f'{i}*{j}={i*j}' for j in range(1,i+1)]) for i in range(1,10)]))
32.深浅拷贝
浅copy:会在内存中新开辟一个空间,存放这个copy的列表,但是列表里面的内容还是沿用之前对象的内存地址。
深copy:会在内存中开辟新空间,将原列表以及列表里面的可变数据类型重新创建一份,不可变数据类型则沿用之前的。
33.IO多路复用
一个线程,通过记录I/O流的状态来同时管理多个I/O,可以提高服务器的吞吐能力
epoll的优点
没有最大并发连接的限制
只有活跃可用的fd才会调用callback函数
内存拷贝是利用mmap()文件映射内存的方式加速与内核空间的消息传递,减少复制开销。(内核与用户空间共享一块内存)
34.nginx的配置
35.数据结构与算法
1.找到整数列表的最大k个数,时间复杂度
2.输入一维数组array和n,找出和值为n的任意两个元素
3.常见的排序算法,时间复杂度分析
4.生成一个旋转矩阵
-
快排
将无序列表的第一项取出作为精准数字,将列表剩余元素大于基准数字的放在右侧,小于的放在左侧。
定义两个指针,low指向列表第一个元素,high指向元素最后一个元素
先比较high指针,大于基准则high减一,小于基准则将此元素赋值给low指针
其次比较low指针,小于基准low加一,大于急诊将此元素赋值给high指针
当low指针与high指针重合时将基准复制当前重复位置
以此递归重复,注意递归结束条件
def fast_sort(alist,start,end): low = start high = end #递归结束的条件 if low > high: return #基准:最左侧的数值 mid = alist[low] #low和high的关系只能是小于,当等于的时候就要填充mid了 while low < high: while low < high: if alist[high] > mid: high -= 1 else: alist[low] = alist[high] break while low < high: if alist[low] < mid: low += 1 else: alist[high] = alist[low] break #当low和high重复的时候,将mid填充 if low == high: alist[low] = mid #or alist[high] = mid break #执行左侧序列 fast_sort(alist,start,high-1) #执行右侧序列 fast_sort(alist,low+1,end) return alist
-
插入排序
插入排序是增量为1的希尔排序
def sort(alist): for i in range(1,len(alist)): while i > 0: if alist[i] < alist[i-1]: alist[i],alist[i-1] = alist[i-1],alist[i] i -= 1 else: break return alist
-
希尔排序
#继续缩小增量 def sort(alist): gap = len(alist) // 2 while gap >= 1: #将增量设置成gap for i in range(gap,len(alist)): while i > 0 : if alist[i] < alist[i-gap]: alist[i],alist[i-gap] = alist[i-gap],alist[i] i -= gap else: break gap //= 2 return alist
-
冒泡排序
def m_sort_final(alist): for i in range(0,len(alist)-1): for j in range(0,len(alist)-i-1): if alist[j] > alist[j+1]: temp = alist[j] alist[j] = alist[j+1] alist[j+1] = temp return alist
链表:https://www.cnblogs.com/bobo-zhang/p/10529330.html
36.linux常见命令
如何查看剩余内存
free -h 或者 top
如何查看端口是否被占用
netstat -anp |grep 端口号 或者 netstat -nultp
如何查看一个程序的PID以及它的所有子进程
ps -ef|grep nginx 或者 pidof nginx
修改IP地址的方法
ifconfig
Linux多路复用的理解
复用的意思是不用每个进程/线程只能操控一个IO,只需一个进程/线程来操控多个IO,复用的是进程/线程。epoll 不仅支持水平触发,而且可以设置为边沿触发。
37.docker
FROM python:3.6-alpine #基于基础镜像
ENV PYTHONUNBUFFERED 1 #设置环境变量
RUN apk update \ #安装依赖
# Pillow dependencies
&& apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev
WORKDIR /app #设置工作目录
RUN pip install pipenv -i https://pypi.douban.com/simple #使用豆瓣源安装依赖
COPY Pipfile /app/Pipfile #拷贝依赖文件到容器中
COPY Pipfile.lock /app/Pipfile.lock
RUN pipenv install --system --deploy --ignore-pipfile
COPY . /app
COPY ./compose/production/django/start.sh /start.sh
RUN sed -i 's/\r//' /start.sh
RUN chmod +x /start.sh
38.mysql中的事务是什么,隔离等级
未提交读:可出现脏读、不可重复读、幻读
不可重复读:不会出现脏读,可能出现不可重复读、幻读
可重复读:不会出现脏读、不可重复读,可能出现幻读
串行化:不会出现脏读、不可重复读、幻读
脏读:A读到了B未提交的数据
不可重复读:A重复读某一数据,B修改提交该数据,A读到了和之前不一样的数据
幻读:A修改了所有数据,B插入(修改)一条未修改的数据,A发现有一条数据未修改
39.函数传参
40.数据库优化
尽量避免使用select * 能用字段名就用字段名。避免查询无用字段
select count(*)会查全表 尽量避免
建表时字段类型能用varchar/nvarchar就不要用char/ncahr
避免频繁的创建和删除临时表 会耗费性能资源 产生大量log
如果使用临时表 在使用的最后一定要显示删除 先trancate table 再drop table
尽量避免大事务操作,提高并发效率
避免向客户端返回大数据量 数据量过大 应考虑需求是否合理
比如你在一个在线网站使用delete和update操作。必然会引发数据库锁
41.深浅拷贝
import copy
copy.copy();浅拷贝,将对象的值引用,不会开辟新内存,无法拷贝对象中的子对象,如果列表改变则自己也改变
copy.deepcopy();深拷贝,开辟新的内存地址,独立对象