Python 和 Java、PHP、C、C#、C++等其他语言的对比?
| python语言,是面向对象、直译式计算机程序设计语言,python语法简洁清晰,具有丰富和强大的类库。 |
| Python是完全面向对象的语言。函数、模块、数字、字符串都是对象。并且完全支持继承、重载、派生、多继承,有益于增强源代码的复用性 |
| java是一种可以撰写跨平台应用软件的面向对象的程序设计语言. |
| PHP是一种通用开源脚本语言。 |
| C语言,它既有高级语言的特点,又具有汇编语言的特点,它是结构式语言。 |
| C++是C语言的继承,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。 |
| C |
简述解释型和编译型编程语言?
| 编译型(需要编译器,相当于用谷歌翻译):编译型语言执行速度快,不依赖语言环境运行,跨平台差. |
| 解释型(需要解释器,相当于同声传译):解释型跨平台好,一份代码,到处使用,缺点是执行速度慢,依赖解释器运行 |
8bit=1bytes
yield和send
| yield 用于从生成器函数中返回一个值,并暂停执行直到下一次调用; |
| send 用于在生成器函数中将一个值发送到当前位置并继续执行直到下一次暂停 |
PEP8规范
| 使用空格来表示缩进,不要用tab |
| 和语法相关每层缩进都要用4个空格 |
| 每行字符数不超过79 |
| 文件中函数与类用两个空格隔开 |
| 在同一类中函数,各方法之间一个空行隔开用 |
GC机制(垃圾回收机制)
| 一般高级语言为了保证内存的使用效率,都会有垃圾回收机制。 |
| python的垃圾回收机制通过三种方式来做的:引用计数,标记清除,和分代回收。 |
| 引用计数是有多少变量指向它,他的引用计数就是几,没用变量指向它,他的内存就会被回收掉。但他会出现循环引入的问题。 |
| 标记清除就是为了解决引入计数存在的循环引入的问题。 |
| -首先是标记阶段,他会把所有的活动对象打上标记,然后把那些没有标记的对象进行回收。 |
| -然后他会循环引入的内存空间打上标记然后回收掉。 |
| 分代回收python把对象分为三代: |
| 一开始,对象在创建的时候放在一代中,如果在一次一代的垃圾回收检查中,该对象存活下来,就会放到第二代中,同理在第二代的垃圾检查中,对象存活下来就会放在第三代,后面优先检查第一代中的对象,优先回收,其次一次往上做检查回收。 |
装饰器、生成器、迭代器
| 装饰器:在不改变被装饰函数的代码情况下给被装饰函数或程序添加新的功能.把函数或类作为参数,返回一个新的函数或类。 |
| 加载顺序自下而上,执行顺序自上而下。 |
| 迭代器:在类中定义了__iter__和__next__方法,__iter__方法返回了对象本身,__next__方法,返回下一组数据没有就会抛出异常。 |
| 生成器:使用了 yield 的函数被称为生成器。调用生成器函数时,会返回一个生成器对象。 |
| 有__iter__方法,且返回一个迭代器对象就是可迭代对象 |
| 有__next__就是一个迭代器 |
| 可迭代对象包括 迭代器(生成器)、序列(字符串,列表、元组)、字典 |
| 遍历完会出现Stopiteraction异常 |
| 装饰器有两大特性: |
| 1能把被装饰的函数替换成其他函数. |
| 2装饰器在加载模块时立即执行. |
| |
| 可以被for循环的对象就是可迭代对象 |
| 可以用isinstace(迭代器,iterator)判断是否迭代器 |
| isinstace(可迭代对象,iterable)判断是否可迭代对象 |
| |
| isinstace()检查对象是否类的对象 |
| issubclass()检查类是否super的派生类 |
| |
| class MyDicorator: |
| def __init__(self,func): |
| self.func=func |
| def __call__(self,*args,**kwargs): |
| res=self.func(*args,**kwargs) |
| return res |
| 为什么有了迭代器还有使用生成器? |
| 迭代器与生成器在某些方面都可以实现相似的功能,但他们在实现方式和使用场景上有所不同,迭代器是一个实现了迭代器协议的对象,它可以遍历一个可迭代对象中的元素 |
| 生成器是一种特殊的迭代器,生成器可以暂停和继续执行,直到生成器中的所有元素都都被返回为止。这使得生成器非常适合处理大量数据,而且可以减少内存消耗 |
| |
| 列表使用的是的动态数组,当需要增加或删除元素时,会自动重新分配内存空间。 |
| 字典是底层实现是哈希表,它是一个带索引和存储空间的表,对可哈希对象进行哈希计算,然后对结果进行取余运算,映射到表索引上面,然后对索引存储的空间进行存储和读取操作。 |
| 集合使用哈希表实现,支持常数时间的插入、删除和查找操作。 |
| 字符串通过一块连续的内存空间来存储元素 |
| 数据类型使用 C 语言的数据类型来实现 |
闭包
| 闭包是当一个内嵌函数引用其外部作作用域的变量。 |
| 1必须有一个内嵌函数 |
| 2内嵌函数必须引用外部函数中的变量 |
| 3外部函数的返回值必须是内嵌函数 |
函数递归
| 在调用一个函数的内部又调用自己,所以递归的本质就是一个循环的过程,它的大前提就是递归调用一定要在某一层结束,如果不结束,会形成一个死循环. |
匿名函数
| 就是定义函数没有名字,通常会在简单运算。 |
| 好处: |
| 不用担心跟其他函数名起冲突。用完后立即释放节约内存。 |
python是值传递还是引用传递?
| 值传递:一个数据值可以被多个变量名绑定,将其中一个变量名当做参数传入函数中,原来的值以及其他指向这个值的变量名不会受到影响 |
| 引用传递:一个数据值可以被多个变量名绑定,将其中的一个变量名当做参数传入函数中,原来的值以及指向这个值的变量名都会受到影响 |
| 严格意义上来讲,python既不是值传递也不是引用传递,python有自己的传递方式,规则是: |
| 如果传递的是不可变类型,在函数中修改,就不会影响原来的变量 |
| 如果传递的值是可变类型,在函数中修改、添加个别元素,会影响原来的变量。如果是重新复制,例如a=新的列表,那么就不会影响原来的变量 |
| 可变类型有:列表、集合、字典 |
| 不可变类型:数字,字符串,元组 |
python设计模式
| 设计模式是面对各种问题进行提炼和抽象而形成的解决方案(23种) |
| 主要分为三大类: 创建类设计模式、结构类设计模式、行为类设计模式 |
| 创建类设计模式(5种):单例模式,工厂模式,建造者模式、原型模式 |
| 单例模式是指:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 |
| 单例模式的优点 |
| 1、由于单例模式要求在全局内只有一个实例,因而可以节省比较多的内存空间; |
| 2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用; |
| 3、单例可长驻内存,减少系统开销。 |
| 结构类设计模式(7种):代理模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式、桥梁模式 |
| 行为类设计模式(11种):策略模式、责任链模式、命令模式、中介者模式、模板模式、迭代器模式、访问者模式、观察者模式、解释器模式、备忘录模式、状态模式 |
魔法方法
| __new__:是在实例创建之前被调用的,用于创建实例,然后返回该实例对象,是个静态方法。 |
| __init__:是当实例对象创建完成后被调用的,用于初始化一个类实例,是个实例方法。 |
| __str__:对象被执行打印操作的时候自动触发 |
| __call__:对象加括号调用的时候自动触发 |
| __getattr__:对象. 不存在的名字的时候自动触发 |
| __getattribute__:对象. 名字会自动触发,有它的存在就不会执行__getattr__ |
| __setattr__:给对象添加或修改数据的时候自动触发 |
| __delattr__:删除属性的时候会触发 |
| __enter__:当对象被当作with上下文管理操作的开始自动触发,并且该方法返回as后面的变量名就会接收到什么 |
| __exit__:with上下文管理语法运行完毕之后自动触发(子代码结束) |
| |
| __new__和__init__区别: |
| 1. __new__是构造方法,__init__是初始化函数。 |
| 2.__new__通常不需要手动定义,一般在元类编程中使用,控制类的生成过程。 |
| 3.__new__第一个被执行,然后执行__init__绑定实例变量。 |
| 4.__new__必须有返回值,返回值是该类的实例,它会被__init__函数接收,通常叫做self变量 |
| |
| |
| 使用new创建单例模式,单例模式创建一个对象,其他对象可以重复的使用不会占用内存空间,可以在__new__方法中使用 if not hasatte(cls,'_ins'):进行判断如若没有就创建cls._ins,使用关键字super继承objct的new方法返回_ins对象 |
| |
如何自定制上下文管理器?
| 一个对象如果实现了__enter__和__exit__方法,那么这个对象就支持上下文管理协议,及with语句。 |
| 上下文管理协议适用于那些进入和退出之后自动执行一些代码的场景,比如文件、网络连接、数据库连接或使用锁,s使用事务的编码场景等。比如当我们使用sqlarchemy时,将session.commit()和session.close()写在__exit__中。 |
| 使用: |
| class ComonSession: |
| def __enter__(self): |
| print('进入with语句块时执行此方法,此方法如果有返回值会赋值给as声明的变量') |
| self.session=session |
| return self.session |
| def __exit__(self, exc_type, exc_val, exc_tb): |
| self.session.close() |
| with ComonSession() as session: |
| session.filter() |
| print('上下文管理器结束了') |
反射
| 利用字符串操作对象的数据和方法 |
| 1.hasattr()判断对象是否含有某个字符串对应的属性名或方法名 |
| 2.getattr()根据字符串获取对象对应的属性名(值)或方法名(函数体代码) |
| 3.setattr()根据字符串给对象设置或者修改数据 |
| 4.delattr()根据字符串删除对象里面的名字 |
接口
| 接口泛指实体把自己提供给外界的一种抽象化物(可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被内部修改而不影响外界其他实体与其交互的方式. |
| 接口就是规范只需要知道接口,按照这个接口做你具体做的事情,就可以融合到整个系统中了。 |
| 在项目中接口在项目就是一个业务逻辑,面向接口编程就是先把客户的业务提取出来 |
| 常见的接口一种是http接口,一种只web service接口 |
| http接口就是get,POST,PUT,DELETE |
| -get和post区别 |
| 1方式get参数直接放到了url里面,post是把参数放到了表单里面 |
| 2get长度有限2M左右post没有大小限制 |
| 3get参数放到浏览器中不安全,post在表单中会稍对安全 |
RESTful规范
| 一种设计和开发Web服务的架构风格,其核心思想是将所有的Web操作视为HTTP协议的标准操作(GET、POST、PUT、DELETE等),并且所有的操作都是无状态的. |
| 1协议:使用https协议 |
| 2域名:api部署的专属域名 |
| 3版本:可以把版本号放在HTTP头信息 |
| 4路径名字使静态 |
| 5method:请求方式 |
| 6过滤:在url上传参形式搜索条件 |
| 7状态码:自定义的响应状态码 |
| 8错误处理,状态码4开头使用error作为key值 |
| 9返回结果:针对不同的操作返回不同的结果 |
| 10最好做到Hypermedia:返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。 |
oop编程(面向对象编程)
| 面向对象编程有三大特征:封装,继承,多态 |
| 封装:把一堆数据属性与方法数据放在一个容器中,这个容器就是对象。让对象可以通过 "." 来调用对象中的数据属性与方法属性。 |
| 继承:是子类可以继承父类的数据属性与方法属性,并可以对其进行修改或使用。 |
| 多态:指的是一类事物有多种形态,一个抽象类有多个子类,不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度 |
| |
| 鸭子类型:python面向对象中描述接口的一个概念,区分与其他编程语言, |
| python不需要显示的继承一个接口(类),只要类中有对应的属性跟方法,我们就称这几个类的对象为同一种类型。 |
| from abc import ABC, abstractmethod |
| 猴子补丁:在程序运行过程中,动态替换的一种技术 |
| 比如在python2中的mysqldb到python3中无法兼容,这时候就可以用pymysql.install_as_mysqlDB()动态替换 |
| 或者在使用gevent动态替换会阻塞的代码,gevent执行猴子补丁会执行代码:monkey.patch_all()同步的代码遇到io操作会阻塞并且释放gil锁,这条线程就会释放cpu的执行。中的猴子补丁执行monkey.patch_all()就会执行猴子补丁。动态将所有的同步代码替换成异步代码,异步代码遇到io不会释放gil锁。time模块和socket模块都会阻塞,执行monkey.patch_all()之后time模块和socket模块已经是包装之后的,不再是原来的了。 |
| 抽象类就是对一堆类共同内容的抽取,包括:属性和方法。 |
python当中如何理解一切皆对象?
| 一切皆对象,包括基本数据类型 |
| 在 Python 中,数字、字符串、布尔值等基本数据类型都是对象。这意味着它们不仅仅是简单的值或变量,而且可以像对象一样被处理。 |
| 对象可以赋值给变量,可以作为函数参数和返回值. |
| 在 Python 中,对象可以赋值给变量,可以作为函数参数和返回值。这意味着我们可以将对象传递给函数,或从函数中返回对象。 |
| 所有对象都有类型和属性. |
python中的type和object有什么关系?
| 首先查看一个类的父类,可以用双下bases,查找一个类由什么实例化而来,用双下class |
| 1.可见任何类都是由type实例化得来 |
| 然后我们再用这两个方法测试type: |
| print(type.__class__) |
| print(type.__base__) |
| 2type是由type本身实例化而来的,而它的父类却是object |
| print(object.__class__) |
| print(object.__base__) |
| 3object没有父类,它是类中最顶端的存在。但是object却是由type实例化得来的 |
| 可以的得到结论: |
| (1)所有类(包括object和type)都是由 type实例化得来的 |
| (2)type的父类是object,object的无父类,object是类中最顶端的存在 |
继承原理 MRO方法
| mro是方法解析顺序:每一个类都会有mro顺序,python会在MRO列表上从左往右一次开始查找基类,直到找到第一个匹配这个属性的类为止。 |
| MRO列表会遵循如下三条准则 |
| 1、子类会先于父类被检查 |
| 2、多个父类会根据它们在列表中的顺序被检查 |
| 3、如果对下一个类存在两个合法的选择 |
| 菱形继承和普通继承,可以使用__mro__来对继承的顺序进行查看 |
| super()代表父类的定义,而不是父类对象 |
绑定方法和非绑定方法
| classmethods:绑定给类的方法,由类来调用,自动将类本身当作第一个参数传入 |
| staticmethod:非绑定方法,不与类和对象绑定,类和对象都可以调用,普通函数,没有自动传值 |
| property:一种特殊属性、访问它时会执行一段功能,用来绑定给对象的方法,将函数对象伪装成数据属性,然后返回值 |
反射、cbv源码简述
| 反射就是通过字符串的形式操作对象相关的属性. |
| hasattr 检测是否含有某属性 |
| getattr 获取属性 |
| setattr 设置属性 |
| delattr 删除属性 |
| CBV源码简述: |
| 根据前端请求方式的不同自动匹配执行对应的方法-在url路由中的views.类 名.as_view()的源码下可以看到是被@classonlymethod修饰的类方法,内部定义闭包函数传参并返回闭包函数名、在dajong启动的时候会执行urls的as_view()产生变 形为views.view,在浏览器提交请求的时候就会触发view方法,通过view下的self 使用类的对象,返回self.dispatch属性、在父类中的dispathc函数通过反射机制就 通过字符串操作对象属性口只有在被完成后才会真正执行,就是可以事先写好逻辑接口,事后实现接口功能 |
类变量和实例变量的区别?
| 类变量中的对象是共有的,实例变量中的对象是私有的。如果一个对象点类名当中的属性修改之后,那么所有对象点这个属性都会拿到修改后的值。当实例的属性被修改后,改变的只有这个实例的值。 |
什么是接口幂等性问题,如何解决?
| 接口幂等性就是用户对同一操作发起一次请求或者多次请求的结果是一致的,不会因为多次点击而产生副作用,get请求幂等,put请求幂等,delete请求幂等,post请求不幂等。我们尤其在涉及数据库修改操作时需要注意保证接口的幂等性。首先,我们要知道什么场景下可能不幂等,在发送请求到收到响应的这一段时间,请求端不知道是否发送了请求,则可能多次的发送了请求,响应端也并没有对多次请求做校验,所以多次处理了相同的请求。 |
| 针对这一点,我们有三种方案保证接口的幂等: |
| 方式一:唯一主键,unique,新增用户名或者手机号唯一,但是不能解决订单 |
| 方式二:token机制: |
| 1.服务端首先需要提供获取token的接口。如果业务存在幂等的问题,就在执行业务之前(比如商城类项目,在进入支付页面时)访问接口,服务端将token保存在redis中,并且返回给前端一份 |
| 2.调用业务的接口(比如支付接口)请求时,携带token |
| 3.服务端判断token是否存在redis中,存在表示第一次请求,然后删除redis中的token,执行业务 |
| 4.如果token不在redis中,就表示是重复操作,直接返回一个标记给前端,就可以避免接口重复执行 |
| 方式三:前端限制按钮只能点击一次 |
什么是GIL锁?有什么作用?
| GIL锁全称全局解释器锁,本质就是一个大的互斥锁,这是Cpython的一种机制,只存在于cpython。作用就是限制多线程同时执行,使得在同一进程内任何时刻仅有一个线程在执行,它限制了一个线程只有获取了gil锁才能执行,没有锁就不能执行。某个线程运行完毕后会释放锁,其他线程才能运行。如果线程运行过程中遇到了io操作,则锁会解开,使其他线程运行。GIL只能确保同进程内多线程数据不会被垃圾回收机制乱删,并不能确保程序里的数据是否安全。 |
| python垃圾回收机制需要有一条线程来做,如果同一时刻有多个线程正在执行,垃圾回收机制可能会把正在其他线程正在使用的变量给回收掉。 |
| GIL锁的弊端:使用Cpython解释器时,GIL锁会使多线程的执行效率很低,无法充分利用CPU资源,基本等同于单线程执行。 |
python线程如何保证运行安全?
| (1)使用互斥锁:即使有GIL锁的存在,也需要使用互斥锁,因为GIL锁只是保证正在执行的线程中的数据不被垃圾回收机制回收,并不能保证数据安全 |
| from threading import Lock |
| (2)使用队列: |
| 多个线程访问同一个资源,访问顺序不确定,可以使用队列来保证线程安全问题。多个线程可以通过put()和get()方法向队列中添加和获取元素 |
| import queue |
| q = queue.Queue() |
| q.put(item) |
| item = q.get() |
| (3)使用信号量(Semaphore):信号量可以控制同时访问共享资源的线程数量,从而避免线程安全问题。 |
常用模块
| 基础os,sys,time,json,pickle,randon,hashlib,re,math,logging |
| 爬虫requests,BeautifulSoup,xpath,gevent,asyncio,twisted |
| logging日志级别:debug、info、warning、error、critical |
| json是可以在不同语言之间交换数据,pickle只在python之间调用 |
| json只能序列化最基本的数据类型,而pickle可以序列化所有的数据类型 |
| requests:请求库 |
| BeautifulSoup:解析库 |
| selenium:自动化测试工具 |
| pymysql:存储库。操作mysql数据库的 |
| Scrapy是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题。 |
进程线程协程
| 进程是资源分配的最小单位,一个应用程序至少有一个进程。 |
| 线程是cpu调度的最小单位,一个进程下至少有一个线程。 |
| 协程:单线程下的并发,程序层面控制任务切换 |
| 进程的实现: |
| 1写一个类,继承Process,重写类的run方法,实例化得到对象,对象.start开启了进程 |
| 2通过Process类实例化得到一个对象,传入任务 ,调用对象.start 开启了进程 |
| from multiprocessing import Process |
| import time |
| def run(name): |
| print('%s is running' % name) |
| time.sleep(3) |
| print('%s finished his run' % name) |
| if __name__ == '__main__': |
| p = Process(target=run, args=('XWenXiang',)) |
| p.start() |
| 线程代码实现: |
| 1写一个类,继承Thread,重写类的run方法,实例化得到对象,对象.start开启了线程 |
| 2通过Thread类实例化得到一个对象,传入任务,调用对象.start开启线程 |
| 协程实现: |
| 早期之前借助于gevent,基于greenlet写的。但是可以借助async(写在函数之前)和await关键字开启协程。 |
| 多线程他遇到io需要系统来进行调度,而使用协程可以手动调度,减少内存的花销。 |
| 可以达到上千的并发 |
进程池线程池
| 定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。 |
| multiprocess.Pool模块 |
什么是Nginx
| ginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器,同时也是一个IMAP、POP3、SMTP代理服务器。可以用作HTTP服务器、方向代理服务器、负载均衡。 |
Nginx应用场景
| http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。 |
| 虚拟主机。可以实现在一台服务器虚拟出多个网站,例如个人网站使用的虚拟机。 |
| 反向代理,负载均衡。 |
Nginx 是如何实现高并发的?
| 异步,非阻塞.nginx采用一个master进程,多个woker进程的模式。 |
| master进程主要负责收集、分发请求.每当一个请求过来时,master就拉起一个worker进程负责处理这个请求. |
| woker进程一般设置为跟cpu核心数一致。nginx的woker进程在同一时间可以处理的请求数只受内存限制,可以处理多个请求。 |
| Nginx负载均衡实现的策略有以下五种: |
| 1轮询.每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某个服务器宕机,能自动剔除故障系统。 |
| 2权重 值越大,分配到的访问概率越高 |
| 3每个请求按访问IP的哈希结果分配,使来自同一个IP的访客固定访问一台后端服务器,并且可以有效解决动态网页存在的session共享问题 |
cookie和session区别?token 是什么?
| cookie |
| 存放在客户端浏览器 |
| 每个域名对应一个cookie,不能跨跃域名访问其他cookie |
| 用户可以查看或修改cookie |
| http响应报文里面给你浏览器设置 |
| 钥匙(用于打开浏览器上锁头) |
| session: |
| 存放在服务器(文件,数据库,redis) |
| 存放敏感信息 |
| 锁头 |
| token 其实就是一串字符串而已,只不过它是被加密后的字符串,它通常使用 uid(用户唯一标识)、时间戳、签名以及一些其它参数加密而成。我们将 token 进行解密就可以拿到诸如 uid 这类的信息,然后通过 uid 来进行接下来的鉴权操作。 |
| token 认证流程: |
| 客户端发起登录请求,比如用户输入用户名和密码后登录。 |
| 服务端校验用户名和密码后,将用户 id 和一些其它信息进行加密,生成 token。 |
| 服务端将 token 响应给客户端。 |
| 客户端收到响应后将 token 存储下来。 |
| 下一次发送请求后需要将 token 携带上,比如放在请求头中或者其它地方。 |
| 服务端 token 后校验,校验通过则正常返回数据。 |
| |
什么是IPC,进程间通信报的方式?
| IPC就是指进程间通信 |
| 进程间通信有两种情况:同一台机器上两个进程通信,不同机器上两个进程通信 |
| 通信方式: |
| 1.python queue可以做进程间通信 |
| 2.消息队列,可以使用redis(一个进程写进去,另一个进程拿出来)、rebbitmq、kafka |
| 3.通过socket套接字,展现形式1:使用一个框架调用另一个框架的接口(例如我们 使用django框架写orm拿到mysql的数据,这就是通过套接字,一个进程从另一个进程中拿到数据)。展现形式2:RPC调用:远程过程调用(微服务使用较多) |
| from multiprocessing import Queue,Process |
| def write(q): |
| for i in ["a", "b", "c", "d"]: |
| q.put(i) |
| |
| print("put {0} to queue".format(i)) |
| def read(q): |
| while 1: |
| result =q.get() |
| print("get {0} from queue".format(result)) |
| def main(): |
| q = Queue() |
| pw = Process(target=write, args=(q,)) |
| |
| pr = Process(target=read, args=(q,)) |
| pw.start() |
| pw.join() |
| pr.start() |
| print(q) |
| |
| if __name__ == '__main__': |
| main() |
| ''' |
| 运行结果 |
| put a to queue |
| put b to queue |
| put c to queue |
| put d to queue |
| <multiprocessing.queues.Queue object at 0x000002BF93EA7670> |
| get a from queue |
| get b from queue |
| get c from queue |
| get d from queue |
| ''' |
进程调度
| 先来先服务、短作业(进程)优先调度算法、时间片轮转、多级反馈队 |
解释为什么计算密集型用多进程,io密集型用多线程?
| 计算密集型是指更多需要cpu参与的程序,io密集型是指阻塞态更多的程序。 |
| 由于GIL锁的存在,即使是多核机器,同一时刻也只能有一个线程在执行,线程需要cpu去调度执行。 |
| 如果是计算密集型,开启多线程不能利用多核优势(cpython中的多线程实际是由于单个线程在不同程序中来回切换产生的),开启多进程能利用多核优势。io操作不消耗cpu,并且多线程可以更快地在不同程序之间切换,开启多线程在一个时间段内可以产生并发效果 |
什么是并发、并行?
| 并发:同一时间段内,执行多个任务的能力 |
| 并行:同一时刻执行多个任务的能力,必须要多cpu执行 |
python如何实现并发?
| 多线程:使得某个线程的IO操作和另一个线程对的CPU计算可以同步执行,避免cpu等待,提高效率 |
| 多进程:multiprocess,利用cpu多核的特点,真正的并行的执行任务 |
| 异步IO:在单线程利用CPU和IO同时执行的原理,实现函数的异步执行 |
| 使用互斥锁对多个线程同时修改数据的操作加锁,保证数据安全 |
| 使用消息队列实现不同进程之间的数据通信 |
| 使用线程池、进程池管理线程、进程的数量,保证程序执行的效率 |
僵尸进程,孤儿进程
| 僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程 |
| 在回收僵尸进程之前, 如果父进程结束了,则僵尸进程变为孤儿进程,进而被init进程接管、回收 |
python数据量大时怎么优化?
| 1.使用列表生成式或者迭代器替代循环 |
| 2.python访问局部变量相较于全局变量消耗资源更少,效率更高,应当减少全局变量使用 |
| 3.在使用django的orm时可以利用惰性查询进行优化,使用defer和only减少数据库的压力 |
| 4.对于数据量大并且查询频率较高的数据量,可以使用python |
| |
| only与defer的区别: |
| only查括号内放的字段 不需要再调用数据库 而查不在括号内的字段,则需要重新调用数据库 |
| defer查括号内的字段需要重新调用数据库 而查不在括号内的字段,不需要重新调用数据库 |
| 所以这两者刚好相反。 |
什么是同步、异步?
| 同步异步是在程序调用的角度来看: |
| 同步是指一件事一件事的做,只有执行完毕前一个任务,才会执行下一个任务 |
| 异步是指:当一个任务开始执行,无需等待该任务完成,就可以切换到另一个任务执行 |
| 同步意味着有序,异步意味着无序。 |
| 异步举例:例如我们在网页上下载一个文件,当我们开始下载时,不需要等它下载完成,即可执行其他操作。 |
什么是阻塞、非阻塞?
| 阻塞、非阻塞是从程序执行对的角度来看: |
| 阻塞:程序在等待某个操作完成期间,自身无法继续干别的事,则称该程序在操作上是阻塞的 |
| 非阻塞:程序遇到需要等待时,自身可以去干别的事,则称该程序在操作上是非阻塞的 |
什么是正向代理和反向代理?
| 正向代理:代理的是客户端(FQ就是正向代理,例如国外网站不能访问,我们先访问到一个代理,然后代理去拿到国外网站的数据返回给我们) |
| 反向代理:代理的是服务端(我们发送的请求会被nginx(或者阿帕奇)代理,然后分发给某一台服务器,对于我们来说我们并不知道我们的请求被哪台服务器处理)(nginx在项目上线时用过) |
黏包现象?
| 因为我们的tcp协议是流式协议,tcp客户端发送的数据就是一些没有结构的字节流一样流向服务端,多个数据报黏在一起,产生黏包现象。 |
| 应对方法: |
| 1.每个包设置结束标志,http协议就采用/r/n作为结束符 |
| 2.每个包设置固定大小的头,头中包含包的大小 |
http协议详情,http协议版本,http一些请求头?
| http协议特点: |
| (1)基于tcp的应用层协议 |
| (2)无状态无连接,不会做会话保持,所以才出现了cookie |
| (3)基于请求响应,服务端不能主动发信息给客户端,于是才出现了websocket |
| 协议详情: |
| (1)请求协议: |
| 请求首行:请求方式(get,post(天然接口不幂等),retrieve,delete,update);请求地址:请求http版本号 |
| 请求头:key-value形式,具体的请求头:cookie,useragent(浏览器相关信息),referer(请求来自于哪个页面),x-forward-for(拿到客户端真实的IP); |
| 请求体:编码方式 |
| (2)响应协议: |
| 响应头:响应状态码、跨域问题(如果是简单请求,我们可以在响应头中添加键值对:{'Access-Control-Allow-Origin':'发起请求的页面'}) |
| 响应体:html格式、json格式 |
| 协议版本: |
| (1)0.9:最初版本,仅支持GET请求 |
| (2)1.0:每次tcp连接客户端只能发送一个请求,服务端响应之后就会关闭这次连接,下次请求需要重新建立tcp连接,也就是不支持keep-alive |
| (3)1.1:引入持久连接,也就是默认不关闭tcp连接,一次连接可以被多个请求复用,不用声明keep-alive,客户端和服务端发现对方一段时间没有活动,就会主动关闭连接(主流还是1.1)。 |
| (4)2.0:引入了多路复用,在1.1版本中即时开启了长连接,请求发送也是串行发送的,对带宽的利用率不够。2.0采用了多路复用的方式,可以并行的发送多个请求。 |
| (5)3.0:3.0版本弃用了TCP协议,使用了UDP协议的QUIC协议来实现。 |
| 1xx客户端的请求已被服务器接受,但还需要继续处理 |
| 2xx代表客户端的请求已成功被服务端接收,并成功处理了这个请求 |
| 200表示请求成功 |
| 201表示请求成功并创建了新的资源 |
| 3xx重定向 |
| 301表示永久重定向 |
| 302表示临时重定向 |
| 4xx表示请求错误 |
| 403服务器理解客户端的请求,但是拒绝执行此请求 |
| 404请求失败,服务器无法找到客户端所请求的资源 |
| 5xx服务器错误 |
| 500服务器内部错误,无法完成请求 |
tcp三次握手和四次挥手?
| 三次握手 |
| 第一次:客户端向服务端发送建立连接请求,【携带一个随机数】(SYN=1,seq=随机数) |
| 第二次:服务端回应客户端的建立连接请求(ACK=1,ack=随机数+1),服务端发送建立连接请求(SYN=1,seq=另一个随机数) |
| 第三次:客户端回应服务端的建立连接请求(ACK=1,ack=另一个随机数+1) |
| 四次挥手 |
| 第一次:客户端向服务端发起断开连接的请求(FIN=随机数) |
| 第二次:服务端收到后,回复这个请求(ACK=1,ack=随机数+1) |
| 第三次:服务端向客户端发起断开连接的请求(FIN=另一个随机数) |
| 第四次:客户端收到后,回复这个请求(ACK=1,ack=另一个随机数+1) |
洪水攻击
| 同一时间有大量的客户端请求建立连接 会导致服务端一直处于SYN_RCVD状态,服务端接收到了大量的syn请求,处于rcvd状态 |
xss攻击是什么?
| XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序 |
osi七层协议,哪七层,每层有哪些,TCP/IP五层结构
| osi七层协议:应用层、表示层、会话层、传输层、网络层、数据链路层、物理连接层 |
| 五层结构:应用层、传输层、网络层、数据链路层、物理连接层 |
| 应用层:有http协议、https协议、ftp协议、dns协议 |
| 表示层:https=http+ssl/tls,ssl处于表示层,主要负责加密解密的工作 |
| 会话层:负责建立、管理和终止会话连接 |
| 传输层:tcp和udp协议属于这一层,端口属于这一层 |
| 网络层:ip协议属于这一层,规定了所有接入互联网对的计算机都必须有一个ip地址,类似于身份证号 |
| 数据链路层:规定了计算机出厂时必须有MAC地址;数据帧、数据报也属于这一层 |
| 物理连接层:确保计算机之间的物理连接介质 |
tcp和udp的区别?udp用在哪里了?
| tcp是面向连接的可靠协议,udp是无连接的不可靠协议,都是处于传输层 |
| (1)tcp协议也称可靠协议。提供的是端到端可靠的字节流,通信之前先建立连接,如果对方没有收到消息会反复发送。udp协议也称不可靠协议,udp是无连接的,发送之前不需要建立连接,是否收到消息也不进行回应,也不保证数据一定送达 |
| (2)udp有较好的实时性,工作效率比tcp高,因为tcp正在传输数据之前需要先建立连接。udp适用于对高速传输和有实时性要求的通信 |
| (3)UDP 的标头大小为 8 个字节,TCP 标头大小为 20 字节。UDP 适合一次性传输较小数据的网络应用,如 DNS,SNMP等。 |
| (4)TCP 面向字节流,实际上是 TCP 把数据看成一连串无结构的字节流,UDP 是面向报文的一次交付一个完整的报文,报文不可分割,报文是 UDP 数据报处理的最小单位 |
| udp:一些聊天软件、dns协议也用的是udp协议 |
| tcp:http、mysql、redis客户端服务通信 |
wsgi,uwsgi,uWSGI,cgi,fastcgi分别是什么?
| CGI:通用网关接口,定义了客户端和服务端如何传数据 |
| FASTCGI:快速通用网关接口,是CGI的升级版,减少网页服务器与CGI程序之间的互动开销,从而使服务器可以同时处理更多的网页请求。常见的FASTCGI:Apache,Nginx |
| wsgi:定义web服务器和web框架之间的接口标准 |
| uWSGI:一个web Server即一个实现了wsgi协议的服务器,处理发来的请求及返回响应 |
| uwsgi:是uWSGI自有的一个协议,定义传输数据的类型 |
websocket协议?
| websocket是一种通信协议,区别于http请求,可在单个tcp连接上进行双工通信,允许服务端主动向客户端推送数据。浏览器和服务器只需要完成一次tcp连接,两者之间就可以建立持久性的连接,并且进行双向数据传输 |
| 使用场景:只要涉及服务端主动给客户端发送信息,就需要使用到wedsocket,例如:实时聊天、服务端发送变化,主动向客户端发送通知(流程审批) |
| 使用:django中使用channles模块实现 |
为什么有了gil锁还要互斥锁?
| gil锁全称全局解释器锁,是解释器级别的锁,gil锁本质也是一个互斥锁。是一个简单的机制确保同一时间只有一个线程访问内存,线程要执行首先要获得gil锁。但它并不是为了数据安全设计的。 |
| 互斥锁是程序级别的锁,为了保证多线程并发操作数据而设置的锁,保证在加锁和释放锁之间,其他线程不能操作。 |
| 互斥锁操作:获得锁:Lock.acquire();释放锁:Lock.release() |
| 例子1:一个进程下有两个线程t1和t2,它们都要去修改全局变量data。假设t1获得gil锁,此时gil抢到了互斥锁。碰巧在修改之前t1遇到了io操作(或者时间片到了),那么gil锁就会被释放被t2抢到,如果t1没有互斥锁那么此时t2直接可以修改data。有了互斥锁的存在此时t2也只能释放gil锁,t1获得cpu可以直接修改data。 |
| 例子2:全局的a=0,线程1和线程2都要去修改全局的a,序号代表执行顺序: |
| 线程1: |
| (1).线程1拿到gil锁 |
| (2).读取a=0 |
| (3).cpu时间片到了,释放gil锁,释放cpu |
| (4).等待下次被调度执行 |
| (10).轮到线程1执行,计算a+1 |
| (11).将结果赋值给a,a=1 |
| (12).释放gil锁 |
| 线程2: |
| (5).线程2获得了gil锁 |
| (6).读取a=0 |
| (7).计算a+1 |
| (8).把结果赋值给a,此时全局a=1 |
| (9).释放gil锁 |
| 以上两个例子说明如果没有互斥锁,会导致数据错乱,出现并发安全问题 |
| 但是我们不可能给一个函数中所有的代码都加上锁,这样会降低代码执行的效率。我们将出现并发安全问题的这段代码称为临界区,加锁也要在临界区加锁。上述例子2中的的临界区为: |
| """ |
| 计算a+1 |
| 把结果赋值给a,此时全局a=1 |
| """ |
乐观锁和悲观锁?
| 乐观锁和悲观锁它们都是一种思想,都是人们定义出来的概念,和语言无关 |
| 并发控制:当程序出现并发的问题时,我们需要保证在并发情况下数据的准确性,以保证当前用户在和其他用户一起操作时,得到的结果和他单独操作时得到的结果是一样的,没有做好并发控制,就可能导致脏读、幻读、不可重复读等问题 |
| 悲观锁:当要对一条数据进行修改时,为了避免数据同时被其他人修改,最好的办法,最好的方法就是直接对该数据进行加锁,让并行变成串行,其他线程想要访问数据时需要阻塞挂起,互斥锁就属于悲观锁 |
| 乐观锁:总是假设最好的情况,每次拿数据都认为别人不会修改,所以不会上锁,只在更新的时候会判断以下在此期间别人有没有更新这个数据,如果更新了,我们就不会修改 |
| 乐观锁的实现: |
| CAS:即比较并替换,是解决多线程并行情况下使用锁造成性能损耗的一种机制。CAS 操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B),执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。CAS会出现ABA的问题:比如我们准备对一个数据进行修改,这个数是1,在准备修改和提交的这段时间内,另一个事物已经将数字修改成了2,然后再修改为1,那么虽然我准备修改的数字是1,但是已经不是原来的那个1了。 |
| 解决ABA问题,我们需要对数据增加一个版本控制字段,只要有人动过这个数据,就将版本增加,修改一次版本是1,在修改一次版本是2,就说明这个数字有人动过。 |
| 版本号控制就是典型的CAS的应用:在数据表中增加一个版本号字段,每次更新数据时将版本号加1,同时将当前版本号作为更新条件,如果当前版本号与更新时的版本号一致,则更新成功,否则更新失败 |
| 使用场景: |
| 并发量:如果并发量不大,可以使用悲观锁解决并发问题,如果并发量非常大的话,悲观锁会产生很严重的性能问题 |
| 响应速度:要求响应速度搞,建议使用乐观锁,成功就成功,失败就失败 |
| 冲突频率:冲突频率很高建议使用悲观锁 |
| 重试代价:重试代价大,建议使用悲观锁 |
| 读多写少:推荐使用乐观锁 |
python的可变和不可变数据类型是什么?
| 可变和不可变数据类型是描述数据类型的一种方式。 |
| 可变数据类型是当数据类型中的某个数据发生改变时,该数据类型绑定的内存地址不发生改变。可变类型有列表、字典、集合 |
| 不可变数据类型是当数据值发生改变时,绑定的内存地址也发生改变,也就是产生一个新的值.不可变类型有数字、字符串、元组 |
深浅拷贝
| 深浅拷贝是指在复制对象时,是否复制其子对象。 |
| 浅拷贝只复制对象本身,而不复制其子对象,而深拷贝则会递归复制对象及其子对象。在Python中,浅拷贝创建一个新对象,但是只复制原始对象的基本数据类型和对象的引用,而不复制对象的子对象。这意味着,如果原始对象包含可变对象(例如列表、字典等),则新对象和原始对象将共享这些可变对象。因此,如果在新对象上进行更改,则原始对象也会受到影响。另一方面,深拷贝创建一个新对象,并递归复制原始对象及其所有子对象。这意味着,如果原始对象包含可变对象,则新对象将包含与原始对象完全相同的副本,而不是共享它们。因此,如果在新对象上进行更改,则原始对象不会受到影响。 |
| copy.deepcopy() |
django请求生命周期?
| django请求生命周期是指用户在输入url到用户看到网页的这个时间段,django后台所发生的事 |
| (1)django中封装了wsgi服务器,监听端口接受本次请求,然后将请求交给框架(django) |
| (2)传送消息到中间件 |
| (3)对请求进行校验或处理,再传送到路由系统中进行路由分发,匹配到对应对的视图函数或者视图类 |
| (4)将请求传输到这个视图函数或者视图类中,进行业务逻辑的判断和处理 |
| (5)调用models中表对象,通过orm拿到数据 |
| (6)将封装了response的响应传输到中间件 |
| (7)通过wsgi再进行封装处理,响应数据到浏览器展示给用户 |
从输入baidu.com到页面返回,中间都是发生了什么?
| 1、域名解析: |
| 浏览器向DNS获取web服务器 www.baidu.com这个域名的 的ip地址 |
| 2、建立TCP连接 |
| 浏览器与对应ip地址的服务器进行TCP链接,端口为80 |
| 3、浏览器执行HTTP协议,发送GET请求,读取对应文件 |
| 4、服务器接收到请求后,返回网页信息 |
| 5.客户端浏览器将这些信息组织成用户可以查看的网页形式 |
django中的信号如何使用,有哪些作用?
| django的信号提供了一种通知机制,他是设计模式中的观察者模式(发布订阅模式),在发生变化的时候自动触发某个函数的执行 |
| 使用:例如我们只要在某个表中插入数据时,就删缓存 |
| 内置信号:如果是内置信号用起来简单,只需要写个函数,跟内置信号绑定,当信号被触发,函数就会执行 |
auth
| 使用 user = authenticate(username=username, password=password)可以获取用户 |
| user.is_authenticated()可以判断是否通过权限 |
| @login_required可以添加校验 |
| create_user()提供的一个创建新用户的方法 |
| create_superuser()创建新的超级用户的方法 |
| check_password(password)检查密码 |
| set_password(password)设置的新密码 作为参数 |
| 扩展auth_user继承内置的 AbstractUser.AUTH_USER_MODEL = "app名.UserInfo" |
F和Q查询
| 需要从数据库中获取 就需要使用F查询 |
| q查询时可以执行更复杂语句使用,并 |是或 |
| 聚合查询aggregate |
| Max, Min, Sum, Count, Avg |
| 分组查询annotate |
drf签发token
| 导入 |
| jwt_payload_handler 使用荷载 |
| jwt_encode_handler 签发token |
| 认证的时候继承BaseAuthentication |
| 使用jwt_decode_handler来验证token |
| |
| |
| jwt和token的区别 |
| jwt是将用户信息加密到token中,服务器不保存用户的信息,只验证token的正确性,只要正确酒桶通过验证,jwt包括三个部分头部荷载和签名 |
| 而token是,用户输入账户和密码发送给服务器,服务器验证用户和密码正确的话会返回一个token字符串用户拿着字符串在后续的请求中会在header头部携带,如果有效返回客户端需要的数据 |
| jwt会保留客户的信息 |
django中间件
| django自带7个中间件 安全中间件,session中间件,一般的中间件,csrf中间件,authentic中间件,消息中间件,劫持保护中间件 |
| 自定义中间件 |
| 继承MiddlewareMixin重写process_request,process_response |
| 在Middleware进行注册 |
Django提高查询效率对的方法有哪些?
| (1)首先每个app中models中的表不能太多,一般不超过5个 |
| (2)Django中默认惰性查询,只要查询结果是queryset,不打印执行结果,那么就不会走sql语句。我们可以使用only和defer关键字,它们都可以点括号内的名字,only查询括号内的字段不需要走sql语句,查括号内没有的字段需要走sql语句。defer刚好相反,查括号内有的字段会走sql语句,查括号内没有的字段会走sql语句。 |
| (3)使用select_related对一对一和一对多的外键关系进行查询。第一次查询的时候它会查询到包含外键的所有字段信息,并且很消耗性能。但是之后的查询就不走数据库prefetch_related() |
django orm如何优化?
| (1)给字段添加索引 |
| (2)在查询大量数据,并且只需要查询一次时使用QuerySets的iterator(),不会产生缓存 |
| (3)在允许的情况下一次性取出所有数据,使用defer和only |
| (4)统计数量时用QuerySet.count()代替len(queryset) |
| (5)在判断queryset时,在queryset末尾点exists()结果会变成一个布尔值。有值是True,没有值是False,执行效率高于if判断 |
| (5)queryset.update()或者delete()可以一次性处理多条数据,无需一条条处理 |
| (6)如果批量插入多条数据,可以使用bulk_create() |
| (7)一对一和一对多使用select_related(),多对对使用prefetch_related() |
django是如何保证运行安全的?
| (1)跨站请求伪造:为了防止请求页面不是恶意请求,需要添加csrf唯一标识。csrf保护的工作原理是检测每个POST请求的随机数,确保了恶意用户不能随意发送恶意请求。 |
| (2)sql注入保护:当我们用django写原生sql校验时,例如校验用户名和密码,如果用户名存在,并且后面加了--(sql当中的注释),那么同样会校验通过。所以我们在django使用原生sql时需要使用cursor.execute(原生sql语句,(username, userpwd))来防止sql注入问题 |
| (3)django可以通过请求头中的referer拿到是哪个页面发送了请求,通过限制策略可以保护用户的隐私 |
drf中有哪些视图类?
| (1)View:视图类在路由系统中会.as_view(),在View中有一个as_view()方法,该方法的返回值是view。所以类名点as_view()相当于类名点view。在as_view()方法中有一个view方法,该方法的返回值是self.dispatch(request, *args, **kwargs),self是视图类的对象,在View类中可以找到dispatch方法,在dispatch方法中通过反射(handler = getattr(self, request.method.lower(), self.http_method_not_allowed))拿到了视图类中的get()方法和post()方法。所以我们在继承View类写接口时候需要在类中定义get()或post()或者其他需要的方法。 |
| (2)APIView:APIView继承了View。类名点as_view(),as_view()方法在APIView中可以找到,并且返回了屏蔽csrf校验的view方法。view方法依旧是View中的闭包函数view,返回dispatch,但是这次的dispatch不在View中而是在APIView中就可以找到,在这里进行三大认证并且封装了最新的request,然后再去视图类中通过反射拿到get()和post()方法等。 |
| 总结:APIView的执行流程 |
| 1 去除了所有的csrf |
| 2 包装了新的request,以后在视图类中用的request是新的request Request类的对象,不是原生的了 |
| 3 在执行视图类的方法之前,执行了3大认证 |
| 4 如果在3大认证或视图函数方法执行过程中出了错,会有异常捕获----》全局异常捕获 |
| 5 以后视图类方法中的request都是新的了 |
orm中的value和value_list有什么区别?
| 都用于获取数据库中的数据,但它们有不同的返回结果和使用方式value返回的一个 QuerySet是一个字典value_list返回的是一个 QuerySet元组或列表 |
简述cors及其原理?
| CORS:全称"跨域资源共享" |
| 是一种浏览器的安全机制,用于限制从一个域名加载的文档或脚本如何与来自不同域名的资源进行交互。浏览器端向服务器发起请求时,会在 HTTP 头部中添加 Origin 字段,用于标识请求来自哪个源。如果服务器允许跨域请求,则需要在响应头部中添加 Access-Control-Allow-Origin 字段,用于指定允许跨域访问的源。 |
| 使用corsheaders包,在app里注册之后添加到中间建立然后配置允许的地址和请求。 |
如何自定义异常类?
| 写一个类继承Exception,重写init方法 |
| class NameDoesNotExist(Exception): |
| def init(self,message,code): |
| self.code=code |
| super().init(message) |
文件操作怎样控制光标移动?
python代码如果部署在用户的服务器上,如何保证代码不泄露?
| (1)代码运行起来之后删除项目(代码运行起来运行在内存中,只要不关机就不会停止服务) |
| (2)pipinstaller运行成可执行文件 |
字典查询10条数据与十万条数据有什么差异
| 1.时间延迟:查询10条数据通常会在几毫秒内完成,而查询十万条数据可能需要几秒钟或几分钟的时间。 |
| 2.内存占用:十万条数据将比10条数据占用更多内存,特别是如果数据集非常庞大时。 |
| 3.索引维护:当数据量增加时,字典的索引维护可能会比较困难,并需要使用更复杂的算法。 |
| 4.查询精度:查询更多的数据通常会带来更高的查询精度和准确性。 |
| 5.搜索结果:当查询十万条数据时,在结果中往往包含更多的相关内容,对于用户来说更有价值。 |
| 6.加载速度:加载十万条数据通常需要更长的时间,这可能会影响用户的体验 |
python中的>>和<<是什么意思?
| >>相当于前面的数除以2的后面的数次方 |
| <<相当于前面的数乘以2后面的数的次方 |
| print(100>>3) |
| print(3<<3) |
| print(5<<3) |
reduce和map怎么使用?
| reduce的工作过程是 :在迭代序列的过程中,首先把 前两个元素(只能两个)传给 函数,函数加工后,然后把 得到的结果和第三个元素 作为两个参数传给函数参数, 函数加工后得到的结果又和第四个元素 作为两个参数传给函数参数,依次类推。reduce函数中有两个参数,第一个是运算的法则,第二个参数是函数或者迭代器: |
| map()方法会将 一个函数 映射到序列的每一个元素上,生成新序列,包含所有函数返回值。也就是说序列里每一个元素都被当做x变量,放到一个函数f(x)里,其结果是f(x1)、f(x2)、f(x3)......组成的新序列: |
django中的session的底层实现原理?
| 设置session:request.session['k1'] = 'xxx' |
| 获取session:request.session.get('k1') |
| 设置session后,响应走的时候 |
| 在中间件SessionMiddleware的process_response()方法内, |
| 首先取出request.session的modify属性,判断是否是true,如果是true,表示在视图函数中修改过session,数据库同步修改; |
| 如果是false,就不修改,返回给前端sessionid:随机字符串; |
| 获取session,请求来的时候 |
| 在中间件SessionMiddleware的process_request()方法内, |
| 通过sessionid获取水机字符串,拿这个随机字符串查找存放session的数据库表, |
| 将查找到的session字典结果存放在request.session中 |
| session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME) |
| request.session = self.SessionStore(session_key) |
django migrate 文件
| migrate 文件后一个会依赖去前一个 |
| 他里面有一个类mirgation继承mirgation里面有dependencies依赖的文件,然后有operation,创建的名字,表结构和版本的名字和记录以及表名 |
| 添加字段时候设置默认值,之前的数据新增加的字段就会为默认值 |
| 添加字段时候允许为空为空,之前的数据新增加的字段就会为空,null=true,或者bank=true |
| 删除的话在models.py删除数据表的生成代码,将所有调用到该数据表的地方注释掉 |
| 也可以migrations.RemoveField进行删除字段 |
| 回退版本 |
| python manage.py migrate <app_name> <migration_name> |
| 也可以用 |
| python manage.py migrate <app_name> 回退到上个版本 |
get请求和post请求的区别?
| (1)post请求更安全,请求的信息不会作为url的一部分,不会保存在浏览器浏览记录中 |
| (2)get请求有url长度的限制,post发送的请求更大 |
| (3)post请求能发送更多的数据类型,get请求只能发送ASCII字符 |
| (4)post请求速度比get请求更慢 |
| (5)post用于修改和写入数据,get一般用于搜索排序和筛选之类的操作 |
django中整形的数据类型分别表示的范围?
| IntegerField:整形(4个字节,32位0或1),表示数字个数:232,表示范:-231-2^31-1 |
| BigIntegerField:整形(8个字节,64位0或1),表示数字个数:264,表示范围:-263-2^63-1 |
| SmallIntegerField:整形(2个字节,16位0或1),表示数字个数:216,表示范围:-215-2^15-1 |
redis的底层的数据?
| String的底层是(简单动态字符串) |
| List的底层是(双向链表和压缩链表) |
| Hash的底层是(压缩链表和哈希表) |
| Set的底层是(整数数组和哈希表) |
| Sorted Set底层(压缩链表和跳表 |
redis持久化方案有哪些?
| 持久化就是所有数据保存在内存中,对数据的更新将异步的保存到硬盘 |
| (1)RDB:某时某刻数据的一个完成备份 |
| :通过save生成RDB持久化,通过bgsave异步生成持久化快照 |
| (2)AOF:客户端每写入一调命令,都会记录一条日志,放到日志文件中,如果出现宕机,可以将数据完全恢复 |
| (2)可以把RDB和AOF一起使用,因为随着命令的逐步写入,并发量的变大, AOF文件会越来越大,就可以把前面的数据保存成rbd快照,后面的数据使用aof来进行优化。 |
缓存雪崩、缓存击穿、缓存穿透
| 缓存雪崩:同一个时刻大量key失效,引起数据库压力过大甚至down机。 |
| 解决方案: |
| 1均匀过期:缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。 |
| 2热点数据永远不过期。 |
| 3Redis高可用,搭建Redis集群,多增加几台Redis服务,一台挂掉,其他还可以继续工作。 |
| |
| 缓存击穿:某个热点key在缓存中没有或已过期,从而产生集中请求。 |
| 解决方案: |
| 1热点key不设置过期时间 |
| 2降低打在数据库上的请求数量,加互斥锁 |
| |
| 缓存穿透:数据在缓存和 DB 中都不存在。导致用户请求都落在DB上,最终可能导致DB承受不住而挂掉 |
| 解决方案: |
| 1接口层增加校验:如用户参数校验,id<=0的直接拦截。 |
| 2无效的key存放Redis:如果是缓存和数据库都查不到的情况下,可以把key保存到Redis中,设置value="null",过期时间可设置短点。防止用户反复用同一个key暴力攻击。 |
| 3布隆过滤器(hash结构) :将数据库中的所有key都存储在布隆过滤器中,查询Redis前先去布隆过滤器查询 key 是否存在,不存在就直接返回,避免了对底层存储系统的查询压力 |
| |
Redis 与 MySQL 双写一致性如何保证?
redis主从复制
| 1. 副本库通过slaveof 127.0.0.1 6379命令,连接主库,并发送SYNC给主库 |
| 2. 主库收到SYNC,会立即触发BGSAVE,后台保存RDB,发送给副本库 |
| 3. 副本库接收后会应用RDB快照 |
| 4. 主库会陆续将中间产生的新的操作,保存并发送给副本库 |
| 5. 到此,我们主复制集就正常工作了 |
| 6. 再此以后,主库只要发生新的操作,都会以命令传播的形式自动发送给副本库. |
| 7. 所有复制相关信息,从info信息中都可以查到.即使重启任何节点,他的主从关系依然都在. |
| 8. 如果发生主从关系断开时,从库数据没有任何损坏,在下次重连之后,从库发送PSYNC给主库 |
| 9. 主库只会将从库缺失部分的数据同步给从库应用,达到快速恢复主从的目的 |
| |
| 主从复制参在问题就是它发生故障与要手动将从主机变成主主机 |
| 哨兵模式可以进行故障的转移不与要手动调节 |
| 1 多个哨兵发现并确认master有问题 |
| 2 选举触一个sentinel作为领导 |
| 3 选取一个slave作为新的master |
| 4 通知其余slave成为新的master的slave |
| 5 通知客户端主从变化 |
| 6 等待老的master复活成为新master的slave |
| 具体就是 |
| 配置主从节点,开启哨兵监控 |
| |
| 当并发达到10万是可以使用集群 |
| 分区可以使用顺序分区和哈希分区虚拟插槽分区(槽的范围0–16383) |
布隆过滤器
| 是一个通过多哈希函数映射到一张表的数据结构,能够快速的判断一个元素在一个集合内是否存在,具有很好的空间和时间效率. |
| BloomFilter 会开辟一个m位的bitArray(位数组),开始所有数据全部置 0 。当一个元素过来时,能过多个哈希函数(h1,h2,h3....)计算不同的在哈希值,并通过哈希值找到对应的bitArray下标处,将里面的值 0 置为 1 ,、 |
| 布隆过滤器判定某个值存在时,其实这个值只是有可能存在;当它说某个值不存在时,那这个值肯定不存在 |
| |
| from pybloom_live import ScalableBloomFilter |
| bloom = ScalableBloomFilter(initial_capacity=100, error_rate=0.001, mode=ScalableBloomFilter.LARGE_SET_GROWTH) |
| url = "www.cnblogs.com" |
| url2 = "www.liuqingzheng.top" |
| bloom.add(url) |
| print(url in bloom) |
| print(url2 in bloom) |
aof文件中的格式有什么含义
| “*3”表示当前命令有三个部分,每部分都是由“$+数字”开头,后面紧跟着具体的命令、键或值。这里,“数字”表示这部分中的命令、键或值一共有多少字节。例如,“$3 set”表示这部分有 3 个字节,也就是“set”命令 |
rabbitmq
| rabbitmq消息队列 |
| 消息队列的优点:1解耦2异步3削峰/限流 |
| 缺点:系统可用性低,外部依赖多,系统复杂 |
| rabbitmq如何保证高可用:单机模式、普通集群模式、镜像集群模式 |
| |
| rabbitmq工作模式 |
| 1 简单模式:单个生产者向单个队列发送消息,单个消费者从队列中接收消息并处理。 |
| 2工作模式:单个生产者向一个队列发送消息,多个消费者从队列中接收消息并处理。消息在被多个消费者接收时会被分配到不同的消费者。 |
| 3发布/订阅模式:生产者将消息发送到称为"交换机"的中间件,然后交换机将消息广播给多个队列,每个队列都有一个与之关联的消费者来处理消息。 |
| 4路由模式:生产者将消息发送到交换机,交换机将消息路由到一个或多个队列,再有与队列关联的消费者来处理消息。 |
| 5主题模式:生产者将消息发送到交换机,交换机和队列之间建立关系,交换机将消息按照匹配主题的规则路由到一个或多个队列中,关联的消费者来处理这些消息。 |
| 避免消息堆积? |
| 1)采用workqueue,多个消费者监听同一队列。 |
| 2)接收到消息以后,而是通过线程池,异步消费。 |
| |
| |
| -如何确保消息正确地发送至RabbitMQ?如何确保消息接收方消费了消息? |
| 需要考虑3个可能丢数据的地方:生产端、队列本身、消费端 |
| |
| 生产端开启 confirm 模式,在生产者那里设置开启 confirm 模式之后,你每次写的消息都会分配一个唯一的 id,然后如果写入了RabbitMQ 中,RabbitMQ 会给你回传一个 ack 消息,告诉你说这个消息 ok 了。如果 RabbitMQ 没能处理这个消息,会回调你的一个 nack 接口,告诉你这个消息接收失败,你可以重试。而 且你可以结合这个机制自己在内存里维护每个消息 id 的状态,如果超过一定时间还没接收到这个消息的回调,那么你可以重发。 |
| |
| 队列本身:就是 RabbitMQ 自己弄丢了数据,这个你必须开启 RabbitMQ 的持久化,就是消息写入之后会持久化到磁盘,设置持久化有两个步骤:创建 queue 的时候将其设置为持久化,第二个是发送消息的时候将消息的 deliveryMode 设置为2 |
| |
| 消费端:就是你必须关闭 RabbitMQ 的自动 ack,通过自己的一个 api 来调用就行,然后每次你自己代码里确保处理完的时候,再在程序里 ack。这样的话,如果你还没处理完,不就没有 ack 了?那 RabbitMQ 就认为你还没处理完,消息是不会丢的。 |
| |
| -如何保证队列的消息不被重复消费? |
| 比如针对数据库,你拿到这个消息做数据库的insert操作给,这个消息做一个唯一主键,就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。 |
| 如果是redis进行set操作就不用管,如果是接口就需要手动去冲 |
celery相关
| Celery是一个异步任务队列,它可以让你把耗时的、异步的任务,放到后台执行 |
| celety包括三大组件: |
| 1消息中间件:Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis |
| 2任务执行单元:Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。 |
| 3任务执行结果存储用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, redis等 |
| |
| 先导入celery库 实例化出一个对象 需要制定一个名称 一个消息代理和一个结果存储地址再定义任务函数 使用@app.task装饰器装饰 函数需要返回结果 |
| 启动celery celery -A应用名 worker -l info |
| 后续通过任务函数delay方法执行该异步任务即可 |
| |
| celery 的架构一般被认为是一层的,由以下组件构成: |
| 客户端: 客户端负责创建任务,并将任务发送到消息代理(Message Broker) 中。Celery 提供了多种客户端,如 Python API、Django 应用程序、命令行工具等 |
| 消息代理: 消息代理负责接收客户端发送的任务,并将任务分发给工作者 (Worker) 。Celery 支持多种消息代理,如 RabbitMQ、Redis、Amazon SQS 等。 |
| 工作者:工作者负责处理任务,并将处理结果返给消息代理。Celery 支持多种工作者类型,如本地进程、分布式进程、协程等。 |
APScheduler执行定时任务
| 触发器 |
| 存储器 |
| 执行器 |
| 调度器 |
| 创建任务,创建blockingscheduler对象,向对象中添加任务和触发器以及事件, |
| 然后使用start()启动任务 |
| |
celery异步任务执行的流程?
| 1.创建一个 Celery 实例,填入关键三个参数:broker, backend, include |
| 2.在 include 中注册 task 文件,在该文件内编写任务,使用 Celery 实例装饰(如:@app.task) |
| 3.使用 delay() 函数,将异步任务推入 Celery 任务队列。 |
| 4.当推入队列的异步任务被处理时,Celery 会去寻找可用的 worker 来运行任务。 |
| 5.任务在 worker 上执行完成后,worker 会将结果存储到 backend(如 Redis 或数据库等)。 |
| 6.访问另一个接口,获取该结果。 |
| |
| 总之,异步任务的执行流程如下:创建任务 -> 推入任务队列 -> 执行任务 -> 返回结果 -> 查询结果 |
linux常用命令
| ps aux:查看进程 |
| netstat nlp |grep 端口号:查看端口占用情况 |
| kill -9 进程号:强制停掉进程 |
| 查看内存:cat /proc/meminfo、free -h |
| ping:查看与服务端的连接状态 |
| echo:将文本写入文件 |
| hostname -l:显示网络IP地址 |
| ip addr show:显示IP地址 |
| ifconfig:显示虚拟机IP地址 |
| sudo chmod -R 777 [文件] 赋予文件权限 |
| mv 文件/* ./ 将本层目录移动到上一层 |
| alias 设置别名 |
| linux三剑客 |
| awk 格式化文本 -F添加分割符 -V 设置变量 |
| grep 查找匹配文本 |
| send 编辑文本 -i 插入行 |
linux中find 与 grep 的区别?
| 如果你需要搜索文件系统中的文件和目录,那么使用 find 是更合适的选择。 |
| 如果你需要在文件中搜索文本,那么使用 grep 更加适合 |
Mysql基础
| 1、 FROM:对FROM子句中的前两个表执行笛卡尔积(交叉联接),生成虚拟表VT1。 |
| 2、 ON:对VT1应用ON筛选器,只有那些使为真才被插入到TV2。 |
| 3、 OUTER (JOIN):如果指定了OUTER JOIN(相对于CROSS JOIN或INNER JOIN),保留表中未找到匹配的行将作为外部行添加到VT2,生成TV3。如果FROM子句包含两个以上的表,则对上一个联接生成的结果表和下一个表重复执行步骤1到步骤3,直到处理完所有的表位置。 |
| 4、 WHERE:对TV3应用WHERE筛选器,只有使为true的行才插入TV4。 |
| 5、 GROUP BY:按GROUP BY子句中的列列表对TV4中的行进行分组,生成TV5。 |
| 6、 CUTE|ROLLUP:把超组插入VT5,生成VT6。 |
| 7、 HAVING:对VT6应用HAVING筛选器,只有使为true的组插入到VT7。 |
| 8、 SELECT:处理SELECT列表,产生VT8。 |
| 9、 DISTINCT:将重复的行从VT8中删除,产品VT9。 |
| 10、 ORDER BY:将 VT9中的行按ORDER BY子句中的列列表顺序,生成一个游标(VC10)。 |
| 11、 TOP:从 VC10的开始处选择指定数量或比例的行,生成表TV11,并返回给调用者。 where子句中的条件书写顺序 |
| 聚合函数: |
| AVG(col)返回指定列的平均值 |
| COUNT(col)返回指定列中非NULL值的个数 |
| MIN(col)返回指定列的最小值 |
| MAX(col)返回指定列的最大值 |
| SUM(col)返回指定列的所有值之和 |
| GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果 |
| 数学函数: |
| ABS(x) 返回x的绝对值 |
| BIN(x) 返回x的二进制(OCT返回八进制,HEX返回十六进制) |
| mysql约束、 |
| 唯一约束,非空约束,主键约束,默认约束,外键约束 |
| 触发器 |
| create trigger 触发器名 before | after 触发事件 |
| on 表名 for each row 执行语句 |
数据库三大范式
| 第一范式(1NF):保证数据库中每一列必须具有原子性,也就是数据表中的每一个字段都是不可再拆分的最小数据单元。 |
| 第二范式(2NF):在满足第一范式的基础上,如果表是单主键,那么主键以外的列必须完全依赖于主键。如果表是复合主键,那么主键以外的列必须完全依赖于主键,并且不能依赖于主键的一部分(其中一个或几个字段)。 |
| 第三范式(3NF):在满足第二范式的基础上,表中每一个非主键列都必须和主键直接相关,非主键列和主键之间不能传递依赖,它们之间是相互独立的。 |
mysql有哪些索引类型,分别有什么作用?
| 1.普通索引是mysql中最基本的索引类型,它没有任何限制,唯一的任务就是加快对数据库的访问速度。普通索引允许在定义索引的列中插入重复值和空值。 |
| 举例:在 tb_student 表中的 id 字段上建立名为 index_id 的索引: |
| CREATE INDEX index_id ON tb_student(id); |
| 2.唯一索引:不是为了提高访问速度而是为了避免数据重复。唯一索引的值必须唯一,允许有空值。如果是组合索引,那么组合的值必须唯一。创建唯一索引通常使用 UNIQUE 关键字 |
| CREATE UNIQUE INDEX index_id ON tb_student(id); |
| 3.主键索引(聚簇索引):专门为主键字段创建的索引,也属于索引的一种。主键索引是一种唯一索引,如果不存在主键,隐藏一个主键,不允许重复或者为空。创建主键索引通常使用 PRIMARY KEY 关键字。不能使用 CREATE INDEX 语句创建主键索引。 |
| 4.联合索引(组合索引或多列索引):组成主键的字段为多个,多个字段组成唯一的索引。 |
| 5全文索引:是一种用于快速搜索文本内容的索引类型。它允许在文本列中进行关键字搜索,而不仅仅是普通的字符串匹配。使用全文索引可以提高搜索性能,并且支持高级搜索功能 |
| |
| 全文索引满足一下条件: |
| 表必须使用MyISAM存储引擎 |
| 要创建全文索引的列必须使用CHAR、VARCHAR或TEXT类型 |
| 要创建全文索引的列必须是表的一个普通列,而不能是主键或唯一键 |
| |
mysql当中的索引什么时候会失效?
| 1.违反最左前缀法则 |
| 如果索引有多列,要遵守最左前缀法则 |
| 即查询从索引的最左前列开始并且不跳过索引中的列 |
| 2.在索引列上做操作:计算、函数、自动手动转换类型 |
| 3.使用不等号:!= <> |
| 4.like以通配符开头('%abc') |
什么是事务,MySQL是如何支持事务的?
| 事务就是一段sql语句的批处理,但是这个批处理是一个原子 ,不可分割,要么都执行,要么回滚(rollback)都不执行。 |
| 事务具体四大特性,也就是经常说的ACID : |
| 1.原子性:所有操作要么全部成功,要么全部失败回滚 |
| 2.一致性:事务执行之前和执行之后都必须处于一致性状态。 |
| 3.隔离性:数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离 |
| 4.持久性:一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的, |
| 即使遭遇故障依然能够通过日志恢复最后一次更新在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务 |
| |
| MYSQL 事务处理主要有两种方法: |
| 1、用 BEGIN, ROLLBACK, COMMIT来实现 BEGIN 开始一个事务 ROLLBACK 事务回滚 COMMIT 事务确认 |
| 2、直接用 SET 来改变 MySQL 的自动提交模式: SET AUTOCOMMIT=0 禁止自动提交 SET AUTOCOMMIT=1 开启自动提交 |
| |
| 事务的隔离级别: |
| 1.read uncommitted(未提交读):事务中的修改即使没有提交,对其他事物也都是可见的。事务可以读取未提交的数据,这一点也称为‘脏读’。 |
| 2.read committed(已提交读):大多数数据库默认的隔离级别。一个事务从开始直到提交之前所做的任何操作对其他事物都是不可见的,事务中的数据如果没有最终提交,对其他事物可见的都是硬盘当中真正的数据。解决了脏读和数据丢失,但会出现一个事务范围内两个相同的查询出现了不同的结果,也就是不可重复读。 |
| 3.repeatable read(可重复读,mysql默认的隔离级别):在开始读取数据(事务开启)时,不再允许修改操作,这样就可以保证在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,能够解决‘脏读’(因为读期间不能进行修改操作),不能解决‘幻读’(依然可以允许增加操作)。幻读是指当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插了新的记录,所以我原来的事物再次插入这条重复的数据时无法插入。InnoDB和XtraDB通过多版本并发控制(MVCC)及间隙锁策略解决该问题 |
| 4.serializable(可串行化):强制事务串行执行,很少使用该级别。一个事务执行完毕之后再执行另一个事物,执行效率低。可以避免脏读、不可重复读、幻读。 |
| |
脏读、不可重复读、幻读是什么?mysql5.7以后默认的隔离级别是什么?
| 脏读:指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了不一定存在的数据,这就是脏读 |
| 不可重复读:指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况 |
| 幻读:并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读 |
左连接,右连接,内连接,全连接是什么?
| 数据通常不在一个表中,这就涉及到连表操作,表间联系的方式有很多: |
| 左连接:以左表为基准,将左表所有的数据展示出来,按照on后面的对应条件分别对应右表中的数据,没有值就用空补齐 |
| 右连接:以右表为基准,将右表中所有的数据展示出来,按照on后面的对应条件分别对应左表中的数据,没有值就用空补齐 |
| 全连接:以左右两表数据为基准,左右两表的数据都展示,没有的数据用空替代 |
union和union all的区别?
| union和union all前后都跟select出来的结果。union会自动对取出的数据进行去重,并且进行排序。union all不会去除重复的数据 |
mysql主从配置的流程大体:
| 1)master会将变动记录到二进制日志里面; |
| 2)master有一个I/O线程将二进制日志发送到slave; |
| 3)slave有一个I/O线程把master发送的二进制写入到relay日志里面; |
| 4)slave有一个SQL线程,按照relay日志处理slave的数据; |

mysql分库分表
| 分库分表有垂直分库分表和水平分库分表 |
| 垂直分库分表的话就是以我们的用户表为例,我们所有用户的表会根据楼栋的不同分到不同的数据库中,几个数据库组合起来才是我们真正的用户表。 |
| 水平分表的话比如我们的用户表和订单表不在同一个数据库中他们组合起来才能执行真正的业务 |
| 分库分表的策略的话,可以使用范围分片比如根据id号,取模分片也就是取余分片还有哈希分片,根据hash相同字段分到一起。 |
mysql查看binlong日志
| 使用 mysqlbinlog -d longfilename 查看指定数据库的相关操作 |
| purge master logs before '年月日时分秒'的日志文件 |
如何开启慢日志查询?
| 1 执行 SHOW VARIABLES LIKE “%slow%”,获知 mysql 是否开启慢查询 slow_query_log 慢查询开启状态 |
| long_query_time 设置超过多少秒就算慢查询 |
| 它的慢查询文件会放到slow_query_log_file |
什么是qps,tps,并发量,pv,uv
| -qps:Queries Per Second,每秒查询率,一台服务器每秒能够响应的查询次数 |
| -tps:Transactions Per Second,是每秒处理的事务数,包括一条消息入和一条消息出,加上一次用户数据库访问 |
| -并发量:系统同时处理的请求数量 |
| -PV(Page View):页面访问量,即页面浏览量或点击量,用户每次刷新即被计算一次。可以统计服务一天的访问日志得到 |
| -UV(Unique Visitor):独立访客,统计1天内访问某站点的用户数。可以统计服务一天的访问日志并根据用户的唯一标识去重得到 |
| -DAU(日活)DAU(Daily Active User),日活跃用户数量。常用于反映网站、app、网游的运营情况。DAU通常统计一日(统计日)之内,登录或使用了某个产品的用户数(去除重复登录的用户),与UV概念相似 |
| -MAU(Month Active User):月活跃用户数量,指网站、app等去重后的月活跃用户数量 |
数据库怎么优化查询效率?
| 1、储存引擎选择:如果数据表需要事务处理,应该考虑使用InnoDB,因为它完全符合ACID特性。 |
| 如果不需要事务处理,使用默认存储引擎MyISAM是比较明智的 |
| 2、分表分库,主从。 |
| 3、对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引 |
| 4、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描 |
| 5、应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描 |
| 6、应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描 |
| 7、Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志 |
| 8、对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。 |
数据库的优化?
| 1.优化索引、SQL 语句、分析慢查询; |
| 2.设计表的时候严格根据数据库的设计范式来设计数据库; |
| 3.使用缓存,把经常访问到的数据而且不需要经常变化的数据放在缓存中,能节约磁盘IO |
| 4.优化硬件;采用SSD,使用磁盘队列技术(RAID0,RAID1,RDID5)等 |
| 5.采用MySQL 内部自带的表分区技术,把数据分层不同的文件,能够提高磁盘的读取效率; |
| 6.垂直分表;把一些不经常读的数据放在一张表里,节约磁盘I/O; |
| 7.主从分离读写;采用主从复制把数据库的读操作和写入操作分离开来; |
| 8.分库分表分机器(数据量特别大),主要的的原理就是数据路由; |
| 9.选择合适的表引擎,参数上的优化 |
| 10.进行架构级别的缓存,静态化和分布式; |
| 11.不采用全文索引; |
| 12.采用更快的存储方式,例如 NoSQL存储经常访问的数据**。 |
Mysql集群的优缺点?
| 优点: |
| 99.999%的高可用性 |
| 快速的自动失效切换 |
| 灵活的分布式体系结构,没有单点故障 |
| 高吞吐量和低延迟 |
| 可扩展性强,支持在线扩容 |
| 缺点: |
| 存在很多限制,比如:不支持外键 |
| 部署、管理、配置很复杂 |
| 占用磁盘空间大、内存大 |
| 备份和恢复不方便 |
| 重启的时候,数据节点将数据load到内存需要很长的时间 |
| |
你用的Mysql是哪个引擎,各引擎之间有什么区别?
| 主要 MyISAM 与 InnoDB 两个引擎,其主要区别如下: |
| InnoDB 支持事务,MyISAM 不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而 MyISAM就不可以了; |
| MyISAM 适合查询以及插入为主的应用,InnoDB 适合频繁修改以及涉及到安全性较高的应用; |
| InnoDB 支持外键,MyISAM 不支持; |
| InnoDB 不支持 FULLTEXT 类型的索引; |
| InnoDB 中不保存表的行数,如 select count() from table 时,InnoDB;需要扫描一遍整个表来计算有多少行,但是 MyISAM 只要简单的读出保存好的行数即可。注意的是,当 count()语句包含 where 条件时 MyISAM 也需要扫描整个表; |
| 对于自增长的字段,InnoDB 中必须包含只有该字段的索引,但是在 MyISAM表中可以和其他字段一起建立联合索引;清空整个表时,InnoDB 是一行一行的删除,效率非常慢。MyISAM 则会重建表; |
| InnoDB 支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like '%lee%' |
Mysql数据库如何分区、分表?
| 分表可以通过三种方式:Mysql集群、自定义规则和merge存储引擎。 |
| 分区有四类: |
| RANGE 分区:基于属于一个给定连续区间的列值,把多行分配给分区。 |
| LIST 分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。 |
| HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的 |
| 这些行的列值进行计算。这个函数可以包含MySQL 中有效的、产生非负整数值的任何表达式。 |
| KEY 分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL 服务器提供其自身的哈希函数。必须有一列或多列包含整数值。 |
Sql注入是如何产生的,如何防止?
| 程序开发过程中不注意规范书写sql语句和对特殊字符进行过滤,导致客户端可以通过全局变量 |
| POST和GET提交一些sql语句正常执行。产生Sql注入。下面是防止办法: |
| a. 过滤掉一些常见的数据库操作关键字,或者通过系统函数来进行过滤。 |
| b. 在PHP配置文件中将Register_globals=off;设置为关闭状态 |
| c. SQL语句书写的时候尽量不要省略小引号(tab键上面那个)和单引号 |
| d. 提高数据库命名技巧,对于一些重要的字段根据程序的特点命名,取不易被猜到的 |
| e. 对于常用的方法加以封装,避免直接暴漏SQL语句 |
| f. 开启PHP安全模式:Safe_mode=on; |
| g. 打开magic_quotes_gpc来防止SQL注入 |
| h. 控制错误信息:关闭错误提示信息,将错误信息写到系统日志。 |
| i. 使用mysqli或pdo预处理。 |
NoSQL和关系数据库的区别?
| 1关系型数据库存在特定结构的表中,nosql没有特定结构的表。 |
| 2关系型数据库必须定义好表和字段结构后才能添加数据,而nosql不需要先定义表结构。 |
| 3关系型数据库是用外键跟其他表相关联,nosql是直接把结果集放到原数据中。 |
| 4关系型数据库JOIN表链接方式查询方式对多个数据集中的数据做查询,nosql使用非规范化的数据存储方式存储数据。 |
| 5关系型数据库不允许删除已经被使用的外部数据,NoSQL随时删除任何数据。 |
| 6关系型数据库多张表同时更新,如果一张表失败则不会执行后面的sql,nosql没有这种概念 |
| 7关系型数据库查找性能不如nosql |
公司镜像仓库
Dockerfile用过吗?常永命令有哪些?
| Dockerfile是由一系列命令和参数构成的脚本文件,可以不基于容器而直接构件出一个新的镜像。 |
| 命令: |
| FROM centos:7 |
| MAINTAINER max |
| ENV name max |
| RUN ... |
| WORKDIR 目录 |
| |
| form 镜像 |
| maintainer 作者 |
| wokerdir 工作目录 |
| run 输入命令 |
| expose 端口 |
| env 设置环境变量 |
| cmd 启动服务 |
| |
| COPY 与 ADD 的区别 |
| COPY 的 SRC 只能是本地文件,其他用法一致 |
| entrypoint和cmd都是⽤来指定容器启动时运⾏的命令, |
| cmd在运⾏docker run命令时容易被覆盖,⽽entrypoint不容易被覆盖。如果你 |
| 希望你的docker镜像只执⾏⼀个具体程序,不希望⽤户在执⾏docker run的时候 |
| 随意覆盖默认程序,建议⽤entrypoint。 |
| entrypoint和cmd可以组合使⽤,这样cmd的内容会作为参数传给entrypoint指 |
| 令,实际执⾏时变为:<entrypoint> “<cmd>”。这样可以灵活地在docker run |
| 的时候指定需要的参数。 |
| entrypoint和cmd都⽀持两种写法:shell表示法和exec表示法。shell表示法会 |
| ⽤/bin/sh -c来执⾏命令,⽽exec表示法会直接执⾏命令。exec表示法可以避免 |
| ⼀些shell表示法的问题,⽐如信号处理和僵⼫进程。 |
镜像传到官方仓库
| 1在远端创建标签 |
| 2给镜像打上标签 docker tag |
| 3登录 docker login |
| 4提交 docker push 仓库:版本 |
docker-compose
| docker-compose up |
| 使用YAML文件来配置我们应用程序的服务 |
| depends_on:依赖于前面的服务 |
| images镜像 |
| environment环境 |
| version版本 |
| service服务 |
| build构建 |
| ports端口 |
| volumes容器 |
| network:网络 |
| docker-compose up启动 |
如何理解python中函数被称为一等公民?
| 在Python中,函数被称为一等公民(first-class citizens),这意味着函数可以像其他数据类型一样进行操作,例如: |
| 可以赋值给一个变量 |
| 可以添加到集合对象中 |
| 可以作为参数传递给函数 |
| 可以当做函数的返回值 |
介绍一下MVVM
| Model(模型) |
| 模型是指代表真实状态内容的领域模型(面向对象),或指代表内容的数据访问层(以数据为中心)。 |
| View(视图) |
| 就像在MVC和MVP模式中一样,视图是用户在屏幕上看到的结构、布局和外观 |
| ViewModel(视图模型) |
| 视图模型是暴露公共属性和命令的视图的抽象。MVVM没有MVC模式的控制器,也没有MVP模式的 |
| presenter,有的是一个绑定器。在视图模型中,绑定器在视图和数据绑定器之间进行通信。 |
Vue的生命周期方法有哪些?一般在哪一步发送请求?
| beforeCreate |
| created 中进行异步请求 |
| beforeMount |
| mounted |
| beforeUpdate |
| updated |
| beforeDestroy |
| destroyed |
v-if 和 v-show 的区别
| v-if :条件不满足时不渲染此节点。 |
| v-show :条件不满足时控制样式将此节点隐藏。 |
vue间通信
| 1父传子:使用自定义属性方式 在子组件中通过props获取数据 |
| 2子传父:使用自定义事件,在子组件中通过$emit自定义属性,在父组件中写函数接收参数, |
| 3通过ref属性 通过this.$ref.组件 拿到组件对象 |
| 4vuex |
| 5localStorage\sessionStorage\cookie |
在Git中,可以使用以下命令回退到先前的提交
| git log:查找要回退的提交的哈希值。 |
| git reset:使用该命令回退到先前的提交。有三种不同的选项,它们会影响回退的方式 |
| git clone 克隆指定仓库 |
| git status 查看当前仓库状态 |
| git add 将文件添加到暂存区 |
| git commit 将文件提交到服务器 |
rbac权限控制
| -rbac:是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便 |
| -用户表:用户和角色多对多关系, |
| -角色表 |
| -一个角色可能有多个权限----》 |
| -开发角色:拉取代码,上传代码 |
| -财务角色:开工资,招人,开除人 |
| -权限表:角色和权限是多对多 |
| -通过5张表完成rbac控制:用户表,角色表,权限表, 用户角色中间表, 角色权限中间表 |
| -如果某个人,属于财务角色,单只想要拉取代码权限,不要上传代码权限 |
| -通过6张表:django的admin----》后台管理就是使用这套权限认证 |
| 用户表, |
| 角色表, |
| 权限表, |
| 用户角色中间表, |
| 角色权限中间表 |
| 用户和权限中间表 |
jira项目管理工具
MongoDB
flask
| flask路由管理 |
| flask可以使用@route装饰器进行路由配置,从而将http请求映射都相应的视图函数上,经过查看源码可以知道,他的内部是调用的了add_role_url函数进行配置路由的 |
| 请求扩展 |
| flask内置了一些请求钩子,他会在请求来的时候的某些时间进行触发函数执行 |
| 请求扩展有before_first_request, |
| before_request:在每个请求处理前执行,用户处理一些预处理逻辑,例如验证用户登录状态,检查权限等。 |
| after_request:在每个请求处理之后执行,例如增加相应头信息,记录日志等 |
| 闪现 |
| 闪现是一种在请求之间传递的信息机制 |
| 可以在上次请求出现异常会进行存储,在下次请求来的时候可以拿出来,使用,拿出来后数据就被删除了。 |
| 全局request |
| 全局request是线程安全的,它是使用的flaks自己编写的local对象,把每个请求所在的线程id或协程id的请求对象进行春初,后续使用它会自己从local对象中跟据线程id或协程id把request对象拿出来。 |
| 全局session |
| 全局session管理用户会话数据, |
| 全局session是线程安全的,他是使用的local对象,把每个请求所在的线程id或者协程id的请求对象进行存储,后续使用可以在根据线程id或协程id拿出来使用。 |
| 使用session需要先在配置文件设置一个密钥,用于加密和解密会话数据。 |
| 蓝图 |
| 蓝图是一种组织视图和静态文件等资源的方式,使用蓝图我们可以将应用程序按功能模块分隔,使得程序更容易开发,测试和维护。 |
| SQLAlchemy |
| sqlchemy是一个基于python实现的orm框架,该框架立在db api上,使用关系对象映射进行数据库操作,简而言之就是将类和对象转换成sql,然后使用数据api执行sql获取执行结果 |
xpath语法
| xpath是一种用于在xml和html文档种定位元素的语言,在使用xpath时,可以通过路径表达式来定位元素 |
| 选择元素:使用元素名来选择元素//div |
| 选择属性:使用@符合例如 //div[@class=‘box’] |
node.js
| node.js是js的运行环境,一个事件驱动、非阻塞式I/O的模型,轻量而又高效。 |
| 用node.js安装vue的环境 |
| 安装vue最新脚手架 |
| 用 vue create 项目名进行配置 |
Pandas
| Python一个扩展程序库,用于数据分析 |
| import pandas as pd |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?