└── README.md /README.md: -------------------------------------------------------------------------------- 1 | ## 面试知识点简单汇总(自测) 2 | ### 招聘网站的一般要求汇总(面试造火箭系列): 3 | 具备开发高并发引擎能力 4 | 熟悉HTTP,TCP/IP等常用协议原理 5 | 熟悉Docker相关理念及核心技术 6 | 精通SQL和NoSQL数据库体系架构设计及高可用性解决方案; 7 | 熟悉mysql,redis,mongo等常用数据库,具有数据库开发和设计能力; 8 | 熟悉linux系统,会熟练编写多进程多线程的程序,熟悉网络编程; 9 | 熟悉python异步IO 10 | 熟练使用Linux系统,掌握基本命令,可编写简单的shell脚本 11 | 了解异步框架、集群与负载均衡,消息中间件,容灾备份等技术; 12 | 完成系统 API 接口等开发工作; 13 | 14 | ### Python知识点: 15 | 写一个简单的python socket编程 16 | python2.x 与python3.x的主要区别 17 | python新式类和旧式类的区别 18 | 请简述线程\进程\协程的特性 19 | 什么是闭包? 20 | Python的实例方法,类方法,静态方法之间的区别及调用关系 21 | Python内存管理和垃圾回收机制 22 | Python的装饰器内部实现原理 23 | 描述你知道的设计模式及各模式特点 24 | 常用算法(冒泡,二叉树,快排, 堆排序等) 25 | 线程池的原理和实现 26 | 解释一下 Django 和 Tornado 的关系、差别 27 | 解释下Http协议的特点 28 | model之F/Q操作, 写一个Q示例 29 | simple\_tag用法 30 | 写一个字典推导式 31 | Python中单下划线和双下划线 32 | 什么是迭代器 33 | 分别用__new__方法和装饰器实现单例模式 34 | 简述Python的作用域以及Python搜索变量的顺序 35 | GIL线程全局锁 36 | Python-copy()与deepcopy()区别 37 | select,poll和epoll 38 | 可变与不可变类型; 39 | 浅拷贝与深拷贝的实现方式、区别;deepcopy如果你来设计,如何实现; 40 | __new__() 与 __init__()的区别; 41 | 你知道几种设计模式; 42 | 编码和解码你了解过么; 43 | 列表推导list comprehension和生成器的优劣; 44 | 什么是装饰器;如果想在函数之后进行装饰,应该怎么做; 45 | 手写个使用装饰器实现的单例模式; 46 | 使用装饰器的单例和使用其他方法的单例,在后续使用中,有何区别; 47 | 手写:正则邮箱地址; 48 | 介绍下垃圾回收:引用计数/分代回收/孤立引用环; 49 | 多进程与多线程的区别;CPU密集型适合用什么; 50 | 进程通信的方式有几种; 51 | 介绍下协程,为何比线程还快; 52 | range和xrange的区别(他妹的我学的py3…); 53 | 将IP地址字符串(比如“172.0.0.1”)转为32位二进制数的函数。 54 | 55 | ### 算法排序部分 56 | 手写快排;堆排;几种常用排序的算法复杂度是多少;快排平均复杂度多少,最坏情况如何优化; 57 | 手写:已知一个长度n的无序列表,元素均是数字,要求把所有间隔为d的组合找出来,你写的解法算法复杂度多少; 58 | 手写:一个列表A=[A1,A2,…,An],要求把列表中所有的组合情况打印出来; 59 | 手写:用一行python写出1+2+3+…+10\*\*8; 60 | 手写python:用递归的方式判断字符串是否为回文; 61 | 单向链表长度未知,如何判断其中是否有环; 62 | 单向链表如何使用快速排序算法进行排序; 63 | 手写:一个长度n的无序数字元素列表,如何求中位数,如何尽快的估算中位数,你的算法复杂度是多少; 64 | 如何遍历一个内部未知的文件夹(两种树的优先遍历方式) 65 | 66 | ### 网络基础部分 67 | TCP/IP分别在模型的哪一层; 68 | socket长连接是什么意思; 69 | select和epoll你了解么,区别在哪; 70 | TCP UDP区别;三次握手四次挥手讲一下; 71 | TIME\_WAIT过多是因为什么; 72 | http一次连接的全过程:你来说下从用户发起request——到用户接收到response; 73 | http连接方式。get和post的区别,你还了解其他的方式么; 74 | restful你知道么; 75 | 状态码你知道多少,比如200/403/404/504等等; 76 | 77 | ### 数据库部分 78 | MySQL锁有几种;死锁是怎么产生的; 79 | 为何,以及如何分区、分表; 80 | MySQL的char varchar text的区别; 81 | 了解join么,有几种,有何区别,A LEFT JOIN B,查询的结果中,B没有的那部分是如何显示的(NULL); 82 | 索引类型有几种,BTree索引和hash索引的区别(我没答上来这俩在磁盘结构上的区别); 83 | 手写:如何对查询命令进行优化; 84 | NoSQL了解么,和关系数据库的区别;redis有几种常用存储类型; 85 | 说说慢查询 86 | 说说数据库的优化 87 | 88 | ### django项目部分 89 | 都是让简单的介绍下你在公司的项目,不管是不是后端相关的,主要是要体现出你干了什么; 90 | 你在项目中遇到最难的部分是什么,你是怎么解决的; 91 | 你看过django的admin源码么;看过flask的源码么;你如何理解开源; 92 | MVC / MTV; 93 | 缓存怎么用; 94 | 中间件是干嘛的; 95 | CSRF是什么,django是如何避免的;XSS呢; 96 | 如果你来设计login,简单的说一下思路; 97 | session和cookie的联系与区别;session为什么说是安全的; 98 | uWSGI和Nginx的作用; 99 | 100 | 扩展阅读: [关于Python的面试题](https://github.com/taizilongxu/interview_python) 101 | 102 | 103 | ## Python基础知识 104 | 105 | ### 将一个字符串逆序,不能使用反转函数 106 | ```python 107 | str = "abcdegfgijlk" 108 | str[::-1] 109 | 'kljigfgedcba' 110 | ``` 111 | 112 | ### 求从10到100中能被3或5整除的数的和 113 | ```python 114 | l = [] 115 | for i in range(10, 100): 116 | if i % 3 == 0 or i % 5 == 0: 117 | l.append(i) 118 | print(l, sum(l)) 119 | ``` 120 | 121 | ### 什么是Python 122 | Python是一种解释型语言, 动态语言, python中一切都是对象, python目前在大数据/人工智能/机器学习/自动化应用十分广泛 123 | 124 | a=1, b=2, 不用中间变量交换a和b的值 125 | ```python 126 | a,b = b, a 127 | ``` 128 | 129 | ### 请用自己的算法, 按升序合并如下两个list, 并去除重复的元素 130 | ```python 131 | list1 = [2, 3, 8, 4, 9, 5, 6] 132 | list2 = [5, 6, 10, 17, 11, 2] 133 | s = sorted(set(list1 + list2)) 134 | print(s)+ 135 | 136 | ``` 137 | 138 | ### 请描述set的用途并举例说明 139 | 去重, 计算交并叉集 140 | 141 | ### python2.x 与python3.x的主要区别 142 | 编码/数据类型 3没有long 增加了bytes xrange / dict的.keys()、.items 和.values()方法返回迭代器 / 3有抽象基类 / 异常 143 | 144 | ### Python里面search()和match()的区别 145 | match()函数只检测RE是不是在string的开始位置匹配, search()会扫描整个string查找匹配 146 | 147 | ### 用Python匹配HTML tag的时候,`<.*>`和`<.*?>`有什么区别 148 | 贪婪和非贪婪 \*号是一个量词 量词后面加? 号表示 非贪婪,也就是尽可能少的匹配 149 | 150 | ### 什么是闭包? 151 | 简单说,闭包就是根据不同的配置信息得到不同的结果, 装饰器就是一种闭包, 闭包有效的减少了函数所需定义的参数数目。 152 | ```python 153 | def line_conf(a, b): 154 | def line(x): 155 | return a*x + b 156 | return line 157 | 158 | line1 = line_conf(1, 1) 159 | line2 = line_conf(4, 5) 160 | print(line1(5), line2(5)) 161 | # (6, 25) 162 | ``` 163 | 164 | 例子中, 如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。利用闭包,我们实际上创建了泛函。 165 | [python闭包的理解说明](https://www.cnblogs.com/lirunzhou/p/5881812.html) 166 | 167 | ### C++/C/JAVA/Python之间的区别? 168 | * python: 快速开发应用程序 169 | * java: 健壮的大型软件 170 | * C++: 需求效率的软件 171 | * C: 操作系统及驱动 172 | 173 | ### 内存管理和垃圾回收机制 174 | Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上, 175 | 通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation)以空间换时间的方法提高垃圾回收效率。   176 | 177 | __1. 内存管理&引用计数__ 178 | python创建新对象都是在内存上开辟一个块, 每个对象只存有一份数据, 赋值和复制都是创建了新的引用, 使用的是对象和引用分离策略 179 | 在Python中,每个对象都有存有指向该对象的引用总数,即引用计数, 如果引用计数为0, 那这个对象就会被python垃圾回收机制回收 180 | 181 | __2. 标记-清除机制__ 182 | 基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。 183 | 同时为了保证效率, Python只会在垃圾达到一定阈值时,垃圾回收才会启动。 184 | 185 | __3. 分代回收策略__ 186 | 这一策略的基本假设是,存活时间越久的对象,越不可能在后面的程序中变成垃圾。Python默认定义了三代对象集合,索引数越大,对象存活时间越长。 187 | 188 | ### 动态语言和静态语言的区别 189 | 动态语言(弱类型语言)是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化 190 | 比如一个类中只定义了一个对象的名字和性别, 可以动态为其加入年龄属性 191 | 静态语言(强类型语言)是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型 192 | 强类型语言是一旦变量的类型被确定,就不能转化的语言。 193 | 弱类型语言则反之,一个变量的类型是由其应用上下文确定的。 194 | 静态语言的优势 195 | 由于类型的强制声明,使得IDE有很强的代码感知能力,故在实现复杂的业务逻辑、大型系统, 错误更容易被发现, 调试难度相对低; 196 | 由于静态语言相对比较封闭,使得第三方开发包对代码的侵害性可以降到最低; 197 | 动态语言的优势 198 | 思维不受束缚,可以任意发挥,把更多的精力放在产品本身上; 199 | 集中思考业务逻辑实现,思考过程即实现过程;但代码中的坑可能不被IDE发现, 后期调试相对费力 200 | 201 | ### 字典推导式 202 | ```python 203 | d = {key: value for (key, value) in iterable} 204 | ``` 205 | 206 | ### Python中单下划线和双下划线 207 | `__foo__`:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突。 208 | `_foo`:一种约定,用来指定变量私有,程序员用来指定私有变量的一种方式 209 | `__foo`:这个有真正的意义:解析器用`__classname`、`__foo`来代替这个名字,以区别和其他类相同的命名。 210 | ### 迭代器协议 211 | 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退) 212 | 2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法) 213 | 3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。 214 | 215 | for 循环机制 216 | for循环的本质:循环所有对象,全都是使用迭代器协议。 217 | for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了, 218 | 列表,字符串,元组,字典,集合,文件对象等本质上来说都不是可迭代对象,在使用for循环的时候内部是先调用他们内部的*iter*方法,使他们变成了可迭代对象,然后在使用可迭代对象的*next*方法依次循环元素,当元素循环完时,会触发StopIteration异常,for循环会捕捉到这种异常,终止迭代 219 | 220 | 访问方式常见的有下标方式访问、迭代器协议访问、for循环访问 221 | 222 | ### 迭代器 223 | 迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退 224 | 不像列表把所有元素一次性加载到内存,迭代器是以一种延迟计算(lazy evaluation)方式返回元素,不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合 225 | 迭代器有两个基本的方法 next方法:返回迭代器的下一个元素 \_\_ 方法:返回迭代器对象本身 226 | 227 | ### 生成器 228 | 语法上和函数类似:生成器函数和常规函数几乎是一样的。它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值(只要一个函数内出现了yield,那它就是一个生成器函数,执行这个函数就得到一个生成器) 229 | 自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生StopIteration异常 230 | 状态挂起:生成器使用yield语句返回一个值。yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行 231 | 生成器的唯一注意事项就是:生成器只能遍历一次。 232 | 233 | ### python语法糖 234 | 语法糖指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法, 语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读 235 | 举些例子吧: 236 | 1. `c = [b,a][a>b]` 取两个中的最大值 237 | 2. `lambda`、`filter`、`map`、`reduce`函数 238 | 3. ``list1=[2\*x+1 for x in range(10)]` 239 | 4. 对列表`lst = [1, -2, 10, -12, -4, -5, 9, 2]` 实现排序,按照正的放前面,负的放后面,并且分别按绝对值从小到大。即输出:`[1, 2, 9, 10, -2, -4, -5, -12]`方法是:`lst.sort(key=lambda x: (x < 0, abs(x)))`等同于:`lst.sort(key=lambda x: abs(x))`--->`lst.sort(key=lambda x: x < 0)` 240 | 5. 装饰器 241 | 242 | ### Python的装饰器内部实现原理 243 | 装饰器本质上是一个Python函数,是闭包的一种实现, 它的作用是让其他函数在不需要做任何代码变动的前提下增加额外功能。 244 | 使用装饰器的时候, 解析器把被装饰的函数作为参数传递给装饰器, 然后再返回一个函数对象, 装饰器内部实现需要额外增加的功能和被装饰函数的功能,虽然被装饰函数的调用方法没有改变, 但实际上已经不是原来函数, 而变成了装饰器返回的函数对象 245 | 它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。 246 | 什么是面向切面编程AOP? 247 | 这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。 248 | 249 | ### 简述Python的作用域以及Python搜索变量的顺序 250 | Python作用域简单说就是一个变量的命名空间。代码中变量被赋值的位置,就决定了哪些范围的对象可以访问这个变量,这个范围就是变量的作用域。 251 | 在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域。 252 | Python的变量名解析机制也称为 LEGB 法则:`本地作用域(Local)→当前作用域被嵌入的本地作用域(Enclosing locals)→全局/模块作用域(Global)→内置作用域(Built-in)` 253 | 254 | ### GIL线程全局锁 255 | 线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程 256 | 257 | ### 死锁 258 | 原因: 259 | * 竞争资源 260 | * 程序推进顺序不当 261 | 必要条件: 262 | * 互斥条件 263 | * 请求和保持条件 264 | * 不剥夺条件 265 | * 环路等待条件 266 | 处理死锁基本方法: 267 | * 预防死锁(摒弃除1以外的条件) 268 | * 避免死锁(银行家算法) 269 | * 检测死锁(资源分配图) 270 | * 解除死锁 271 | * 剥夺资源 272 | * 撤销进程 273 | 274 | ### 调度算法 275 | 先来先服务(FCFS, First Come First Serve) 276 | 短作业优先(SJF, Shortest Job First) 277 | 最高优先权调度(Priority Scheduling) 278 | 时间片轮转(RR, Round Robin) 279 | 多级反馈队列调度(multilevel feedback queue scheduling) 280 | 实时调度算法: 281 | 最早截至时间优先 EDF 282 | 最低松弛度优先 LLF 283 | 284 | ### 什么lambda函数(匿名函数),匿名函数有什么局限性 285 | 匿名函数,也就是lambda函数,通常用在函数体比较简单的函数上。匿名函数顾名思义就是函数没有名字,因此不用担心函数名冲突。 286 | 不过Python对匿名函数的支持有限,只有一些简单的情况下可以使用匿名函数。 287 | 288 | ### KISS原则 289 | KISS原则是英语 Keep It Simple, Stupid 的首字母缩写。 290 | KISS原则是指在设计当中应当注重简约的原则。 291 | 292 | ### 简述函数式编程 293 | 在函数式编程中,函数是基本单位,变量只是一个名称,而不是一个存储单元。 294 | 除了匿名函数外,Python还使用`fliter()`,`map()`,`reduce()`,`apply()`函数来支持函数式编程 295 | 296 | ### Python-copy()与deepcopy()区别 297 | —–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。 298 | —–而浅复制并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。 299 | 浅拷贝只拷贝一层, 深拷贝拷贝全部 300 | 第一:非容器类型(不可变对象, 比如数字,字符串和其他原子类型的对象,例如代码,类型和range对象等)没有拷贝一说,浅拷贝是完全用切片操作来完成的。 301 | 第二:如果元组变量只包含原子类型对象,那么深拷贝将不会进行。 302 | 303 | ### 如何捕获异常,常用的异常机制有哪些? 304 | 如果我们没有对异常进行任何预防,那么在程序执行的过程中发生异常,就会中断程序,调用python默认的异常处理器,并在终端输出异常信息。 305 | `try...except...finally`语句:当try语句执行时发生异常,回到try语句层,寻找后面是否有except语句。 306 | 找到except语句后,会调用这个自定义的异常处理器。except将异常处理完毕后,程序继续往下执行。finally语句表示,无论异常发生与否,finally中的语句都要执行。 307 | assert语句:判断assert后面紧跟的语句是True还是False,如果是True则继续执行print,如果是False则中断程序,调用默认的异常处理器,同时输出assert语句逗号后面的提示信息。 308 | with语句:如果with语句或语句块中发生异常,会调用默认的异常处理器处理,但文件还是会正常关闭。 309 | 310 | ### 有用过with statement吗?它的好处是什么?具体如何实现? 311 | with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源, 312 | 比如文件使用后自动关闭、线程中锁的自动获取和释放等。 313 | 314 | 315 | ## 面向对象 316 | 317 | ### 基本概念 318 | 多态\封装\组合\继承 319 | 迭代器和生成器 320 | 321 | ### Python的面向对象和Java面向对象的区别 322 | python可面向对象编程,可以不按照面向对象编程。java就必须面向对象编程了,必须建个类 323 | 324 | ### Python的实例方法,类方法,静态方法之间的区别及调用关系 325 | 在类里面定义的函数就是方法,类方法需要`@classmethod`修饰并且有个隐藏参数 `cls`,实例方法必须有个参数 `self`, 静态方法必须有`@staticmethod`修饰,类和实例都可以访问静态方法,实例可以访问实例方法也可以访问类方法,类可以访问类方法也可以访问实例方法,访问实例方法 326 | 必须要带参数 `self`, 可以理解为类其实也是一个实例,类访问实例方法不带参数会报错的。类本身可以访问函数,实例却不行 327 | 详细: [Python的实例方法,类方法,静态方法之间的区别及调用关系 ](https://www.cnblogs.com/funfunny/p/5892212.html) 328 | 329 | ### python新式类和旧式类的区别 330 | 主要区别是多继承中,新式类采用广度优先搜索,而旧式类是采用深度优先搜索 331 | 332 | ### `__new__`和`__init__`的区别 333 | 创建一个新实例时调用`__new__`,初始化一个实例时用`__init__`,这是它们最本质的区别。 334 | `__new__`是一个静态方法,而`__init__`是一个实例方法。 335 | `__new__`方法会返回一个创建的实例,而`__init__`什么都不返回。 336 | 只有在`__new__`返回一个cls的实例时后面的`__init__`才能被调用。 337 | 单例模式的实现可以使用`__new__`方法 338 | 339 | ### 单例模式__new__方法版本 340 | ```python 341 | class Singleton(object): 342 | def __new__(cls, *args, **kw): 343 | if not hasattr(cls, '_instance'): 344 | orig = super(Singleton, cls) 345 | cls._instance = orig.__new__(cls, *args, **kw) 346 | return cls._instance 347 | 348 | class MyClass(Singleton): 349 | # ... 350 | ``` 351 | 352 | ### 单例模式装饰器版本 353 | ```python 354 | def singleton(cls, *args, **kw): 355 | instances = {} 356 | def getinstance(): 357 | if cls not in instances: 358 | instances[cls] = cls(*args, **kw) 359 | return instances[cls] 360 | return getinstance 361 | 362 | @singleton 363 | class MyClass: 364 | # ... 365 | ``` 366 | 367 | 368 | ## MySQL数据库相关 369 | 370 | ### MySQL练习题 371 | [MySQL练习题参考答案](http://www.cnblogs.com/wupeiqi/articles/5748496.html) 372 | 373 | ### 内联,左外联,右外联,全连接,交叉连接 的区别 374 | 典型多对多联表查询: 375 | ```sql 376 | select man_to_women.nid,man.name as mname, women.name as wname from man_to_women 377 | left join man on man_to_women.man_id = man.nid 378 | left join women on man_to_women.women_id = women.nid 379 | where man.name = 'alex' 380 | ``` 381 | 左联:显示左边表的所有数据,只显示右边表与左边表有关联的数据 382 | 383 | ### 什么是视图?以及视图的使用场景有哪些? 384 | 视图是一种虚拟的表,具有和物理表相同的功能 385 | 只暴露部分字段给访问者,所以就建一个虚表,就是视图。 386 | 查询的数据来源于不同的表,而查询者希望以统一的方式查询,这样也可以建立一个视图,把多个表查询结果联合起来,查询者只需要直接从视图中获取数据,不必考虑数据来源于不同表所带来的差异 387 | 388 | ### 视图作用 389 | 数据库视图隐藏了数据的复杂性。 390 | 数据库视图有利于控制用户对表中某些列的访问。 391 | 数据库视图使用户查询变得简单。 392 | 393 | ### 说一下事务的特性? 394 | __原子性(Atomicity)__:事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行。 395 | __一致性(Consistency)__:几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。 396 | __隔离性(Isolation)__:事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。 397 | __持久性(Durability)__:对于任意已交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出 398 | 399 | ### 什么是存储过程 400 | [简述存储过程](https://www.ilwid.net/posts/3b0cd4ca.html#%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B) 401 | 402 | ### 创建一个完整的存储过程示例 403 | ```sql 404 | delimiter $$ # 修改结束符为$$, 以免程序把begin...end之间的;作为结束符 405 | drop procedure if exitsts proc_p1 $$ # 如果已经存在proc_p1就先删除 406 | create procedure proc_p1( 407 | in i1 int # 需要一个int类型的参数 408 | ) 409 | begin # sql逻辑代码要放在begin...end之间 410 | declare d1 int; # 声明一个d1变量 411 | declare d2 int default 3; # 声明一个默认值为3的d2变量 412 | set d1 = i1 + i2; 413 | select *from man_to_women where nid > d1; 414 | end $$ 415 | deliniter ; # 修改结束附为默认的分号,以免影响其他语句 416 | 417 | # 调用存储过程 418 | call proc_p1(2) 419 | ``` 420 | 421 | ### sql注入原理 422 | sql注入漏洞产生的原因最常见的就是字符串拼接SQL语句,这种漏洞可以利用注释语句绕过验证 423 | 如 `select name from userinfo where name='alex' and password = '888'` 424 | 用户如果在name字段输入 `alex' or 1=1 --f` 就可以成功绕过验证。 425 | 要解决这个问题就不能在程序中拼接sql语句,例如使用pymysql的execute方法,这个方法会自动对用户输入的引号特殊字符做转义 426 | 427 | ### 简单说一说drop、delete与truncate的区别 428 | delete和truncate只删除表的数据不删除表的结构 429 | 速度,一般来说: drop> truncate >delete 430 | delete语句是del,这个操作会放到rollback segement中,事务提交之后才生效; 431 | 如果有相应的trigger,执行的时候将被触发。 432 | truncate,drop是ddl, 操作立即生效,原数据不放到rollback segment中,不能回滚. 操作不触发trigger。 433 | 使用场景: 434 | 不再需要一张表的时候,用drop 435 | 想删除部分数据行时候,用delete,并且带上where子句 436 | 保留表而删除所有数据的时候用truncate 437 | 438 | ### 数据库怎么优化查询效率? 439 | 通常会在WHERE、JOIN ON和ORDER BY使用到字段上加上索引。 440 | 避免查询时判断NULL,否则可能会导致全表扫描。 441 | 避免使用OR来连接查询条件,否则可能导致全表扫描,可以改用UNION或UNION ALL。 442 | 避免LIKE查询,否则可能导致全表扫描。 443 | 不使用SELECT \*,只查询必须的字段,避免加载无用数据。 444 | 能用UNION ALL的时候就不用UNION,UNION过滤重复数据要耗费更多的cpu资源。 445 | 避免Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大 量日志 446 | 447 | 总结如下: 448 | 1、避免模糊查询,如OR、LIKE等,因为会导致全表扫描; 449 | 2、在常用字段加索引,例如WHERE、JOIN ON和ORDER BY使用到字段上应该加索引 450 | 3、尽量避免全局性的读写操作,例如SELECT \* 、Update全部字段 451 | 452 | ### 数据库优化方案? 453 | 1.优化索引、SQL 语句、分析慢查询; 454 | 2.设计表的时候严格根据数据库的设计范式来设计数据库; 455 | 3.使用缓存,把经常访问到的数据而且不需要经常变化的 数据放在缓存中,能节约磁盘 IO; 456 | 4.优化硬件;采用 SSD,使用磁盘队列技术 (RAID0,RAID1,RDID5)等; 457 | 5.采用 MySQL 内部自带的表分区技术,把数据分层不同 的文件,能够提高磁盘的读取效率; 458 | 6.垂直分表;把一些不经常读的数据放在一张表里,节约 磁盘 I/O; 459 | 7.主从分离读写;采用主从复制把数据库的读操作和写入操作分离开来; 460 | 8.分库分表分机器(数据量特别大),主要的的原理就是数据路由; 461 | 9.选择合适的表引擎,参数上的优化; 462 | 10.进行架构级别的缓存,静态化和分布式; 463 | 11.不采用全文索引; 464 | 12.采用更快的存储方式,例如 NoSQL 存储经常访问的数 465 | 466 | ### Mysql 几种锁的区别 467 | * 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 468 | * 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 469 | * 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。 470 | 471 | 三种锁各有各的特点,若仅从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如WEB应用;行级锁更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。 472 | 473 | ### 参考资料 474 | [常见面试题整理--数据库篇](http://blog.csdn.net/weinierzui/article/details/71054964) 475 | 476 | 477 | ## Redis基础及高可用、高并发、集群相关知识 478 | 479 | ### 什么是redis 480 | redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(列表)、set(集合)、zset(sorted set --有序集合)和hashs(哈希类型) 481 | 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的. 482 | 在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是缓存在内存中. 483 | 区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步. 484 | 485 | ### 使用redis有哪些好处? 486 | 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) 487 | 支持丰富数据类型,支持string,list,set,sorted set,hash 488 | 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行 489 | 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除 490 | 491 | ### Redis解决秒杀/抢红包等高并发事务活动 492 | 秒杀开始前30分钟把秒杀库存从数据库同步到Redis Sorted Set 493 | 用户秒杀库存放入秒杀限制数长度的Sorted Set 494 | 秒杀到指定秒杀数后,Sorted Set不在接受秒杀请求,并显示返回标识 495 | 秒杀活动完全结束后,同步Redis数据到数据库,秒杀正式结束 496 | 497 | ### redis数据超过可用内存的处理方式 498 | 1、修改redis.conf中的maxmemory-policy选项,设置删除redis键的淘汰规则 499 | 2、加内存 500 | 3、缩短(或设置)数据过期时间,以释放内存 501 | 4、redis集群 502 | 如果redis数据中,存的是关键数据,怕丢失的数据,那么,redis数据占用的内存,不要超过内存大小的70%(保险起见不要超过55%),以免内存不足!不要期望什么内存淘汰策略!它所做的居然是删数据! 503 | 如果数据是不怕丢的缓存数据,那么可以在redis.conf里,配置如下两项,进行内存数据淘汰(其实是删除) 504 | 505 | ### 什么是高可用架构 506 | 在介绍高可用架构的方案之前,先说一下什么是高可用架构,高可用架构应具备但不限于以下特征: 507 | 主从切换 508 | 很好理解,当其中一台机器的服务宕机后,对于服务调用者来说,能够迅速的切换到其他可用服务,从服务升级为主服务,这种切换速度应当控制在秒级别(几秒钟)。 509 | 当宕机的服务恢复之后,自动变为从服务,主从服务角色切换。主从切换一定是要付出代价的,所以当主服务恢复之后,也就不再替换现有的主服务。 510 | 负载均衡 511 | 当服务的请求量比较高的时候,一台服务不能满足需求,这时候需要多台机器提供同样的服务,将所有请求分发到不同机器上。 512 | 高可用架构中应该具有丰富的负载均衡策略和易调节负载的方式。 513 | 甚至可以自动化智能调节,例如由于机器性能的原因,响应时间可能不一样,这时候可以向性能差的机器少一点分发量,保证各个机器响应时间的均衡。 514 | 易横向扩展 515 | 当用户量越来越多,已有服务不能承载更多的用户的时候,便需要对服务进行扩展,扩展的方式最好是不触动原有服务,对于服务的调用者是透明的。 516 | 517 | ### Redis 高可用 518 | 高可用架构一般都要具备主从复制\切换、负载均衡、易于扩展等特性,如果节点较少可以直接使用Redis集群,Redis集群具备这些特性,只要有一半以上的节点正常就能提供服务;如果规模较大的时候,就可以引入sentinel“哨兵”组件,它能提供监控、提醒、自动故障迁移等服务 519 | [部署高可用的Redis集群架构](http://blog.csdn.net/u013063153/article/details/71191138) 520 | 521 | ### Redis 高并发 522 | 高并发下主要考虑的是Redis集群方案,把流量分散到不同的Redis机器中去。 523 | Redis集群可以从横向和纵向两个方面考虑,增强整体的可用性。 524 | 横向可以从分库剥离,负载均衡,一致性算法方面进行考虑 525 | 纵向可以从副本集,持久化,灾备等方面进行考虑 526 | (即横向集群方案做高并发,纵向做高可用) 527 | 528 | ### redis应用之利用redis高效统计访问量及访问的用户(计数) 529 | 原理:利用setbit方法,设置一个二进制每一位都为0的变量如usercount,通过算法给每一个访客一个唯一的数字ID标识,然后给usercount设置该用户ID位为1即可,通过bitcount usercount命令获取usercount有多少个1即为访客总数。通过这个方法保存1亿个用户的访问数据(总访问量和来访的用户)只需要不足10m的空间,而且非常高效。 使用方法如下: 530 | ```python 531 | set usercount 0 532 | >>> OK 533 | bitcount usercount 534 | >>> 2 # 0的二进制值为0110000,所以为2 535 | setbit usercount 2 0 536 | setbit usercount 3 0 # 以上两句设置usercount的第2、3位为0,此时二进制值为 00000000 537 | setbit usercount 4999 1 # 假设ID为4999的用户来访,设置usercount 的第4999位为1 538 | setbit usercount 3582 1 # 假设ID为3582的用户来访,设置usercount 的第3582位为1 539 | bitcount usercount 540 | >>> 2 # 此时共有4999、3582两个访客,因此总数为2 541 | getbit usercount 4999 542 | >>> 1 # 获取ID为4999的用户的来访状态,如果值为1,则是访客,如果是0则是非访客 543 | ``` 544 | 545 | ### redis 和 mysql 的区别? 546 | redis 是内存数据库,数据保存在内存中,速度快。 547 | mysql 是关系型数据库,持久化存储,存放在磁盘里面,功能强大。检索的话,会涉及到一定的 IO,数据访问也就慢。 548 | 一般需要永久存储的数据使用MySQL,比如用户信息,文章等 549 | 而临时数据或者经常访问的数据就会使用redis,比如用户的session/排行榜/访问计数/Pub Sub 构建实时消息系统/缓存等 550 | 551 | ### Memcache与Redis的区别都有哪些? 552 | 1)、存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis有部份存在硬盘上,这样能保证数据的持久性。 553 | 2)、数据支持类型 Memcache对数据类型支持相对简单。 Redis有复杂的数据类型。 554 | 3)、使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。Redis直接自己构建了VM机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。 555 | 556 | 扩展阅读 557 | [Redis、Memcache和MongoDB的区别](https://www.cnblogs.com/tuyile006/p/6382062.html) 558 | 559 | ### Redis常见的性能问题和解决方法 560 | 1.Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。 561 | 2.如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。 562 | 3.为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。 563 | 4.尽量避免在压力较大的主库上增加从库 564 | 5.为了Master的稳定性,主从复制不要用图状结构,用单向链表结构更稳定,即主从关系为:`Master<--Slave1<--Slave2<--Slave3.......`,这样的结构也方便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以立马启用Slave1做Master,其他不变。 565 | 566 | ### mySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据 567 | 相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略: 568 | volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰 569 | volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰 570 | volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰 571 | allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰 572 | allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰 573 | no-enviction(驱逐):禁止驱逐数据 574 | 575 | ### redis的并发竞争问题如何解决? 576 | Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有2种解决方法: 577 | 1.客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。 578 | 2.服务器角度,利用setnx实现锁。 579 | 注:对于第一种,需要应用程序自己处理资源的同步,可以使用的方法比较通俗,可以使用synchronized也可以使用lock;第二种需要用到Redis的setnx命令,但是需要注意一些问题。 580 | 581 | ### redis持久化 582 | [redis持久化的几种方式(RDB和AOF持久化的优劣比较)](https://www.cnblogs.com/chenliangcl/p/7240350.html) 583 | 584 | ### Redis如果运行过程中崩溃了怎么办。 585 | 这个问题面试官想问的是Redis的数据保障的方法,不然崩溃了除了重启还能怎么办? 586 | Redis有提供数据持久化的功能,一种是快照,一种是AOF。 587 | 快照是在某一个时间点将所有数据写入到磁盘中,AOF是将被执行的命令复制到硬盘中,快照的文件体积要比AOF的文件体积小。前者在恢复时速度比后者快,但是因为是间隔持久化,所以会有一定量的数据丢失。后者因为是实时写入的,所以数据的完整性比较好,如果丢失的话一般也就丢失一秒的数据。 588 | 其次需要做主从复制,这样一份数据可以保存在多台服务器上,且可以避免Redis崩溃到重启完成这段时间内无法提供正常服务,同时从服务器可以分担主服务器的读压力。 589 | 590 | ### Redis集群 591 | Redis集群创建步骤是 592 | 1、在至少3台服务器上安装redis服务 593 | 2、分别修改这些服务器上redis的配置文件并确保它们可以互相访问,然后启动它们 594 | 3、使用Redis 官方提供的redis-trib.rb工具的create命令创建集群 595 | 596 | ### 简单说一下Redis集群的工作原理 597 | redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。 598 | Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。所以我们在测试的时候看到set 和 get 的时候,直接跳转到了7000端口的节点。 599 | Redis 集群会把数据存在一个 master 节点,然后在这个 master 和其对应的salve 之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的 master 节点获取数据。只有当一个master 挂掉之后,才会启动一个对应的 salve 节点,充当 master 。 600 | 需要注意的是:必须要3个或以上的主节点,否则在创建集群时会失败,并且当存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了。 601 | 602 | ### 悲观锁和乐观锁区别,乐观锁适用于什么情况 603 | 悲观锁,每次访问数据的时候都觉得会有别人修改它,所以每次拿数据时都会上锁,确保在自己使用的过程中不会被他人访问。乐观锁每次拿数据的时候都不会上锁,只在更新数据的时候去判断该数据是否被别人修改过。 604 | 大多数的关系数据库写入操作都是基于悲观锁,缺点在于如果持有锁的客户端运行的很慢,那么等待解锁的客户端被阻塞的时间就越长。Redis的事务是基于乐观锁的机制,不会在执行WATCH命令时对数据进行加锁,只是会在数据已经被其他客户端抢先修改了的情况下,通知执行WATCH命令的客户端。 605 | 乐观锁适用于读多写少的情况,因为在写操作比较频繁的时候,会不断地retry,从而降低性能。 606 | 607 | ### MVCC 608 | 在并发读写数据库时,读操作可能会不一致的数据(脏读)。为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问。 609 | 由于,加锁会将读写操作串行化,所以不会出现不一致的状态。但是,读操作会被写操作阻塞,大幅降低读性能。 610 | 而其优化的手段就是,在进行写操作时,将数据copy一份,不会影响原有数据,然后进行修改,修改完成后原子替换掉旧的数据,而读操作只会读取原有数据。 611 | 通过这种方式实现写操作不会阻塞读操作,从而优化读效率。 612 | MVCC全称是Multi-Version Concurrent Control,即多版本并发控制。 613 | 在MVCC协议下每个读操作会看到一个一致性的snapshot,并且可以实现非阻塞的读。MVCC允许数据具有多个版本,这个版本可以是时间戳或者是全局递增的事务ID, 614 | 在同一个时间点,不同的事务看到的数据是不同的。 615 | 616 | ### 参考资料 617 | [数据库SQL优化大总结之 百万级数据库优化方案](https://www.ilwid.net/posts/1f8fcfbf.html) 618 | 619 | 620 | ## 多线程、多进程、协程、异步编程、I/O多路复用 621 | 622 | ### 请简述线程、进程、协程的特性 623 | 进程是系统进行资源分配和调度的最小单位,进程是线程的容器,一个进程可以包含多个线程,进程之间数据不能互相访问 624 | 线程是CPU调度的最小单位,线程是程序执行流的最小单元, 每一个进程都至少有一个线程, 线程之间数据可以共享 625 | 进程线程都是由操作系统调度,python中多线程和多进程都是通过切换上下文来实现,都会耗费额外的系统资源 626 | 协程由程序员调度, 由代码切换来控制, 系统并不知道协程的存在, 各种多并发异步非阻塞模块都是基于协程来实现的 627 | 进程和线程都面临着内核态和用户态的切换问题而耗费许多切换时间,而协程就是用户自己控制切换的时机,不再需要陷入系统的内核态。 628 | Python里最常见的yield就是协程的思想 629 | 630 | ### 线程有几种状态?生命周期是怎样的? 631 | 线程有五种状态:创建、就绪、运行、阻塞、死亡。 632 | 调用start方法时,线程就会进入就绪状态。 633 | 在线程得到cpu时间片时进入运行状态。 634 | 线程调用yield方法可以让出cpu时间回到就绪状态。 635 | 线程运行时可能由于IO、调用sleep、wait、join方法或者无法获得同步锁等原因进入阻塞状态。 636 | 当线程获得到等待的资源资源或者引起阻塞的条件得到满足时,会从阻塞状态进入就绪状态。 637 | 当线程的run方法执行结束时,线程就进入死亡状态。 638 | 639 | ### 进程间通讯的方式有哪些,各有什么优缺点: 640 | 1)管道:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程之间使用。进程的亲缘关系通常是指父子进程关系。 641 | 2)有名管道(FIFO):有名管道也是半双工的通信方式,但是允许在没有亲缘关系的进程之间使用,管道是先进先出的通信方式。 642 | 3)信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 643 | 4)消息队列:消息队列是有消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 644 | 5)信号 ( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 645 | 6)共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。 646 | 7)套接字( socket ) :套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。 647 | 8)文件 648 | 649 | ### 线程池的原理: 650 | 既然是线程池(Thread pool),其实名字很形象,就是把指定数量的可用子线程放进一个"池里",有任务时取出一个线程执行,任务执行完后, 651 | 并不立即销毁线程,而是放进线程池中,等待接收下一个任务。这样内存和cpu的开销也比较小,并且我们可以控制线程的数量。 652 | 653 | ### 线程池的实现: 654 | 线程池有很多种实现方式,在python中,已经给我们提供了一个很好的实现方式:Queue-队列。因为python中Queue本身就是同步的,所以也就是线程安全的,所以我们可以放心的让多个线程共享一个Queue。 655 | 那么说到线程池,那么理应也得有一个任务池,任务池中存放着待执行的任务,各个线程到任务池中取任务执行,那么用Queue来实现任务池是最好不过的。 656 | 657 | 线程安全和非线程安全 658 | 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。如Queue、logging 659 | 非线程安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。如list、set、dict 660 | 661 | ### 异步IO / IO多路复用的原理 662 | [IO多路复用的原理详解](http://www.cnblogs.com/alex3714/articles/5248247.html) 663 | [IO多路复用(番外篇)](http://www.cnblogs.com/alex3714/articles/5876749.html) 664 | [Python Select epoll详解](http://www.cnblogs.com/alex3714/articles/4372426.html) 665 | 666 | ### 简述事件驱动 667 | 1. 有一个事件(消息)队列; 668 | 2. 鼠标按下时,往这个队列中增加一个点击事件(消息); 669 | 3. 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数,如onClick()、onKeyDown()等; 670 | 4. 事件(消息)一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数; 671 | 672 | ### 简述I/O多路复用 673 | I/O多路复用是指单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流。即系统内核缓冲I/O数据,当某个I/O准备好后,系统通知应用程序该I/O可读或可写,这样应用程序可以马上完成相应的I/O操作,而不需要等待系统完成相应I/O操作,从而应用程序不必因等待I/O操作而阻塞。 674 | 与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。比如高并发应用nginx就是用I/O多路复用,它的性能是极佳的。 675 | 目前支持I/O多路复用的系统调用有select,epoll,它们本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。 676 | 677 | ### I/O多路复用和异步I/O的区别 678 | I/O多路复用的本质是同步IO,是阻塞的,而异步I/O是非阻塞的。 679 | 阻塞、非阻塞、IO多路复用,都是同步IO,需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的;异步是非阻塞的,真正的异步IO需要CPU的深度参与。 680 | 使用 select,epoll 的IO多路复用的模型中,虽然进程大部分时间都不会阻塞,但是它仍然要求进程去主动的轮询,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。 681 | 而异步I/O则完全不同。用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。 682 | nginx、tornado、twised等应用,虽然我们习惯性地叫它们为异步IO,但是它们实际上是IO多路复用。因为它们的底层是基于select和epoll实现的。 683 | 真正的异步现在内核支持不完美,实际应用比较少,python中真正支持异步IO的模块是asyncio 684 | 685 | ### select,poll和epoll之间的异同 686 | select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。 687 | 所有的I/O都是轮询的方法,只不过实现的层面不同罢了。 688 | Windows底层只支持select, Linux很早就支持epoll了,tornado底层使用的就是epoll的。 689 | 基本上select有3个缺点: 690 | * 连接数受限(1024) 691 | * 查找配对速度慢 692 | * 数据由内核拷贝到用户态 693 | poll改善了第一个缺点 694 | epoll改了三个缺点。 695 | 696 | ### epoll中et和lt的区别与实现原理 697 | LT:水平触发,效率会低于ET触发,尤其在大并发,大流量的情况下。但是LT对代码编写要求比较低,不容易出现问题。LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心事件丢失的情况。 698 | ET:边缘触发,效率非常高,在并发,大流量的情况下,会比LT少很多epoll的系统调用,因此效率高。但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况。 699 | 700 | 701 | ## 网络编程基础知识 702 | 703 | ### 解释下Http协议 704 | HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。 705 | HTTP协议的主要特点可概括如下: 706 | 1. 支持客户/服务器模式。 707 | 2. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。 708 | 3. 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。 709 | 4. 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。 710 | 5. 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。 711 | 712 | [关于HTTP协议,一篇就够了](https://www.cnblogs.com/ranyonsue/p/5984001.html) 713 | 714 | ### 在浏览器地址栏键入URL,按下回车之后会经历以下流程: 715 | 1、浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址; 716 | 2、解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接; 717 | 3、浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器; 718 | 4、服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器; 719 | 5、释放 TCP连接; 720 | 6、浏览器将该 html 文本并显示内容; 721 | 722 | ### HTTP之状态码 723 | 状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别: 724 | 1xx:指示信息--表示请求已接收,继续处理 725 | 2xx:成功--表示请求已被成功接收、理解、接受 726 | 3xx:重定向--要完成请求必须进行更进一步的操作 727 | 4xx:客户端错误--请求有语法错误或请求无法实现 728 | 5xx:服务器端错误--服务器未能实现合法的请求 729 | 730 | ### 常见状态码: 731 | ```javascript 732 | 200 OK //客户端请求成功 733 | 400 Bad Request //客户端请求有语法错误,不能被服务器所理解 734 | 401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 735 | 403 Forbidden //服务器收到请求,但是拒绝提供服务 736 | 404 Not Found //请求资源不存在,eg:输入了错误的URL 737 | 500 Internal Server Error //服务器发生不可预期的错误 738 | 503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常   739 | ``` 740 | 741 | ### TCP(传输控制协议)与UDP(用户数据包协议)的区别; 742 | 1)TCP提供面向连接的传输,通信前要先建立连接(三次握手机制);UDP提供无连接的传输,通信前不需要建立连接。 743 | 2)TCP提供可靠的传输(有序,无差错,不丢失,不重复);UDP提供不可靠的传输。 744 | 3)TCP面向字节流的传输,因此它能将信息分割成组,并在接收端将其重组;UDP是面向数据报的传输,没有分组开销。 745 | 4)TCP提供拥塞控制和流量控制机制;UDP不提供拥塞控制和流量控制机制。 746 | 747 | ### 什么时候使用TCP协议,什么时候使用UDP协议; 748 | a. 对数据可靠性的要求。对数据要求高可靠性的应用需选择TCP协议,如验证,密码字段的传送都是不允许出错的,而对数据的可靠性要求不那么高的应用可选择UDP传送; 749 | b. 应用的实时性。TCP协议在传送过程中要使用三次握手、重传确认等手段来保证数据传输的可靠性。使用TCP协议会有较大的延迟,因此不适合对实时性要求较高的应用,如VOIP、视频监控等。相反,UDP协议则在这些应用中能发挥很好的作用。 750 | c. 网络的可靠性。由于TCP协议的提出主要是解决网络的可靠性问题,它通过各种机制来减少错误发生的概率,因此,在网络状况不是很好的情况下需选用TCP协议(如在广域网等情况),但是若在网络状况很好的情况下(如局域网等)就不需要采用TCP协议,而建议选择UDP协议来减少网络负荷。 751 | 752 | 为什么早期QQ使用UDP协议 753 | 原因是因为当时没有epoll这种可以支持成千上万tcp并发连接的技术,所以他们使用了udp,然后在udp上面封装了一下,模拟了一下tcp,解决了大并发的问题,之后因为做的很nb了,虽然epoll这种技术出现了,还是没有改回使用tcp了.现在再做类似的东西就不需要使用udp了 754 | 755 | ### 三次握手,四次挥手的详细过程以及作用; 756 | __三次握手__: 757 | 第一次握手是客户端connect连接到server,server accept client的请求之后,向client端发送一个消息,相当于说我都准备好了,你连接上我了,这是第二次握手,第3次握手就是client向server发送的,就是对第二次握手消息的确认。之后client和server就开始通讯了。 758 | 759 | __四次挥手__ 760 | 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。 761 | 收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。CP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。 762 | 断开连接的一端发送close请求是第一次挥手,另外一端接收到断开连接的请求之后需要对close进行确认,发送一个消息,这是第二次挥手,发送了确认消息之后还要向对端发送close消息,要关闭对对端的连接,这是第3次挥手,而在最初发送断开连接的一端接收到消息之后,进入到一个很重要的状态time\_wait状态,这个状态也是面试官经常问道的问题,最后一次挥手是最初发送断开连接的一端接收到消息之后。对消息的确认。 763 | 764 | ### TCP为什么不是两次连接?而是三次握手? 765 | 如果A与B两个进程通信,如果仅是两次连接。可能出现的一种情况就是:A发送完请报文以后,由于网络情况不好,出现了网络拥塞,即B延时很长时间后收到报文,即此时A将此报文认定为失效的报文。B收到报文后,会向A发起连接。此时两次握手完毕,B会认为已经建立了连接可以通信,B会一直等到A发送的连接请求,而A对失效的报文回复自然不会处理。依次会陷入B忙等的僵局,造成资源的浪费。 766 | 767 | ### 网络编程的一般步骤 768 | 对于TCP连接: 769 | 1.服务器端: 1)创建套接字create;2)绑定端口号bind;3)监听连接listen;4)接受连接请求accept,并返回新的套接字;5)用新返回的套接字recv/send;6)关闭套接字。 770 | 2.客户端: 1)创建套接字create; 2)发起建立连接请求connect; 3)发送/接收数据send/recv;4)关闭套接字。 771 | TCP总结: 772 | Server端:create -- bind -- listen-- accept-- recv/send-- close 773 | Client端:create------- conncet------send/recv------close. 774 | 775 | 对于UDP连接: 776 | 1.服务器端:1)创建套接字create;2)绑定端口号bind;3)接收/发送消息recvfrom/sendto;4)关闭套接字。 777 | 2.客户端:1)创建套接字create;2)发送/接收消息sendto/recvfrom;3)关闭套接字. 778 | UDP总结: 779 | Server端:create----bind ----recvfrom/sendto----close 780 | Client端:create---- sendto/recvfrom----close. 781 | 782 | ### 写一个简单的python socket 783 | ```python 784 | import socket 785 | # 服务端 786 | s = socket.socket() 787 | s.bind(('192.168.1.11', '1000')) 788 | s.listen() 789 | conn, addr = s.accept() 790 | data = s.recv(1024) 791 | print(data) 792 | s.send('ok') 793 | s.close() 794 | 795 | # 客户端 796 | c = socket.socket() 797 | c.connect(('192.168.1.11', '1000')) 798 | c.send(b'hello world') 799 | data = c.recv(1024) 800 | print('recv:',data) 801 | c.close() 802 | ``` 803 | 804 | ### GET和POST,有什么区别 805 | 根据HTTP协议,他们根本区别是,简单点儿说,GET用于获取数据,POST用于修改数据。 806 | 另外用法上, 一般GET使用URL或Cookie传参, 而POST将数据放在BODY中, 但HTTP协议没有这样的要求, 技术上说GET和POST与数据如何传递没有关系 807 | 808 | ### apache和nginx的区别 809 | nginx 相对 apache 的优点: 810 | + 轻量级,同样起web 服务,比apache 占用更少的内存及资源 811 | + 抗并发,nginx 处理请求是异步非阻塞的,支持更多的并发连接,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能 812 | + 配置简洁 813 | + 高度模块化的设计,编写模块相对简单 814 | + 社区活跃 815 | apache 相对nginx 的优点: 816 | + rewrite ,比nginx 的rewrite 强大 817 | + 模块超多,基本想到的都可以找到 818 | + 少bug ,nginx 的bug 相对较多 819 | + 超稳定 820 | 821 | ### 怎么保证密码保存和传输是安全的 822 | MD5+Salt+时间戳+sign,这个salt可以随机值(传递给服务端,服务端使用预先约定到的协议进行解密) 823 | 824 | ### CSRF和XSS区别 825 | CSRF重点在请求,XSS重点在脚本 826 | CSRF(Cross-site request forgery)跨站请求伪造 827 | XSS(Cross Site Scripting)跨站脚本攻击 828 | 829 | ### 幂等 Idempotence 830 | HTTP方法的幂等性是指一次和多次请求某一个资源应该具有同样的副作用。(注意是副作用) 831 | 幂等与你是不是分布式高并发还有JavaEE都没有关系。关键是你的操作是不是幂等的。 832 | 一个幂等的操作典型如:把编号为5的记录的A字段设置为0这种操作不管执行多少次都是幂等的。 833 | 一个非幂等的操作典型如:把编号为5的记录的A字段增加1这种操作显然就不是幂等的。 834 | 要做到幂等性,从接口设计上来说不设计任何非幂等的操作即可。 835 | 譬如说需求是:当用户点击赞同时,将答案的赞同数量+1。 836 | 改为:当用户点击赞同时,确保答案赞同表中存在一条记录,用户、答案。赞同数量由答案赞同表统计出来。 837 | 838 | ### RPC 839 | RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。 840 | RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。 841 | RPC使得开发包括网络分布式多程序在内的应用程序更加容易。 842 | 总结:服务提供的两大流派.传统意义以方法调用为导向通称RPC。为了企业SOA,若干厂商联合推出webservice,制定了wsdl接口定义,传输soap.当互联网时代,臃肿SOA被简化为http+xml/json.但是简化出现各种混乱。以资源为导向,任何操作无非是对资源的增删改查,于是统一的REST出现了. 843 | 进化的顺序: RPC -> SOAP -> RESTful 844 | 845 | ### WSGI 846 | WSGI, Web Server Gateway Interface,是Python应用程序或框架和Web服务器之间的一种接口, 847 | WSGI的其中一个目的就是让用户可以用统一的语言(Python)编写前后端。 848 | 849 | ### 中间人攻击 850 | 在GFW里屡见不鲜的中间人攻击(Man-in-the-middle attack,通常缩写为MITM)是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。 851 | 852 | 853 | ## Web 框架之 Django、Tornado 854 | 855 | ### Django请求生命周期 856 | 1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端。请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post,体现在url之中。 857 | 2. url经过Django中的wsgi,再经过Django的中间件,最后url到过路由映射表,在路由中一条一条进行匹配。一旦其中一条匹配成功就执行对应的视图函数,后面的路由就不再继续匹配了。 858 | 3. 视图函数根据客户端的请求查询相应的数据。返回给Django,然后Django把客户端想要的数据做为一个字符串返回给客户端。 859 | 4. 客户端浏览器接收到返回的数据,经过渲染后显示给用户。 860 | 861 | ### 解释下django-debug-toolbar的使用 862 | 使用django开发站点时,可以使用`django-debug-toolbar`来进行调试。 863 | 在`settings.py`中添加`debug_toolbar.middleware.DebugToolbarMiddleware`到项目的`MIDDLEWARE_CLASSES` 内。 864 | 865 | ### 如何进行Django单元测试 866 | 单元测试存在的意义就是,可以让我们放心的重构代码,可以在重构代码的时候省下测试重构的代码能否正确运行的时间 867 | [Django 单元测试](https://code.ziqiangxuetang.com/django/django-test.html) 868 | [Django单元测试基础知识](https://www.jianshu.com/p/34267dd79ad6) 869 | 870 | ### model之F/Q操作 871 | F操作,使用查询条件的值,F()允许Django在未实际链接数据的情况下具有对数据库字段的值的引用, Python都不需获取F内的值, 直接操作后保存, 用法场景例如 字段+1(加减乘除运算) 字段比较如日期比较 872 | ```python 873 | from django.db.models import F, Q 874 | models.UserInfo.objects.filter().update(salary=F('salary')+500) 875 | ``` 876 | 877 | ### Q操作,构造搜索条件, 用于构造复杂的查询条件如各种筛选过滤 878 | ```python 879 | con = Q() 880 | q1 = Q() 881 | q1.connector = 'OR' 882 | q1.children.append(('id', 1)) 883 | q1.children.append(('id', 2)) 884 | q2 = Q() 885 | q2.connector = 'OR' 886 | q2.children.append(('status', '在线')) 887 | con.add(q1, 'AND') 888 | con.add(q2, 'AND') 889 | models.Tb1.objects.filter(con) 890 | ``` 891 | 892 | ### simple\_tag用法 893 | ```python 894 | from django import template 895 | register = template.Library() 896 | 897 | @register.simple_tag 898 | def foo()... 899 | ``` 900 | 901 | ### ORM是什么? 902 | ORM 全称是 Object/Relation Mapping,即对象/关系数据库映射。可以讲ORM理解成一种规范,它概述了这类框架的基本特征,完成面相对象的编程语言到关系数据库的映射。 903 | ORM可以当成是应用程序和数据的桥梁。 904 | 905 | 基本映射方式 ORM工具提供了持久化类和数据表之间的映射关系,通过这种映射关系的过度,程序员可以很方便地通过持久化类实现数据表的操作。实际上,所有的ORM工具大致都遵循相同的映射思路。 906 | 映射关系: 907 | 1、数据表映射类 908 | 持久化映射到一个数据表。程序使用这个持久化类来创建实例,修改属性,删除实例时,系统自动对这个表进行操作。 909 | 2、数据表的行映射对象(实例) 910 | 持久化类会生成很多实例,每个实例就对应数据表中的一行记录。 911 | 3、数据的列(字段)映射对象的属性 912 | 当程序修改某个持久化对象的指定属性时,ORM将会将其转换成对应数据表中的指定数据行、指定 列的操作。 913 | 914 | ### 一般的ORM包括以下四部分: 915 | 一个对持久类对象进行CRUD操作的API; 916 | 一个语言或API用来规定与类和类属性相关的查询; 917 | 一个规定mapping metadata的工具; 918 | 一种技术可以让ORM的实现同事务对象一起进行dirty checking, lazy association fetching以及其他的优化操作。 919 | 920 | ### 使用ORM的好处 921 | 应用程序不再直接访问底层数据库,而是以面向对象的操作转换成底层的SQL操作。 922 | 就是把持久化对象的保存、修改、删除等操作,转换成对数据库的操作。 923 | 924 | ### 解释一下 Django 和 Tornado 的关系、差别 925 | python web框架分两种, 一种是django 一种是其他, 其他里又分两种, 一种是tornado, 一种是其他 926 | django最大的特点是大而全, Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以“插件”形式服务于整个框架 927 | Tornado是异步非阻塞式服务器,速度快。底层基于epoll 928 | 929 | ### Django生产环境部署 930 | Django + Uwsgi(动态请求) + Nginx(静态请求) 实现生产环境部署 931 | [Django + Uwsgi + Nginx 实现生产环境部署](https://www.cnblogs.com/alex3714/p/6538374.html) 932 | 933 | ### Tornado 的核心是什么? 934 | Tornado 的核心是 ioloop 和 iostream 这两个模块,前者提供了一个高效的 I/O 事件循环,后者则封装了 一个无阻塞的 socket 。通过向 ioloop 中添加网络 I/O 事件,利用无阻塞的 socket ,再搭配相应的回调 函数,便可达到梦寐以求的高效异步执行。 935 | 936 | ### 怎么使用Tornado 异步非阻塞 937 | 非阻塞这部分代码主要就在ioloop.py里 938 | Future对象 代表将来执行或没有执行的任务的结果。 939 | 两大功能: 940 | 1\挂起当前请求,线程可以处理其他请求 941 | 2\如果给future设置值,当前挂起的请求返回并释放 942 | 事件循环 使用 gen.coroutine 装饰器 943 | 生成器 yield future 944 | 945 | 异步非阻塞tornado模型中使用select或者epoll监听用户请求,当接收到用户请求的时候,首先生成一个Future对象,再把这个socket和future存入一个字典;hold住这个请求并把该请求交给相应的函数处理求,当该函数处理完成后会通过回调函数把结果和状态交给future对象, 这时tornado会把future的数据返回给用户,在这整个过程中, tornado程序是非阻塞的. 946 | 947 | ### Tornado 异步模式 948 | 当发送GET请求时,由于方法被 @gen.coroutine装饰且yield 一个 Future对象,那么Tornado会等待, 949 | 等待用户向future对象中放置数据或者发送信号,如果获取到数据或信号之后,就开始执行doing方法。 950 | 异步非阻塞体现在当在Tornaod等待用户向future对象中放置数据时,还可以处理其他请求。 951 | 注意:在等待用户向future对象中放置数据或信号时,此连接是不断开的。 952 | 953 | ### @gen.coroutine的作用 954 | gen.coroutine主要是使用协程的方式实现类似异步的处理效果 955 | 它简化异步代码的编写,避免写回调函数,加快开发效率,提高代码可读性,通过结合 pyhton 的 yield 语句实现协程 956 | 通过 @gen.coroutine 修饰的函数返回值变为 Future, 在调用结束的时候会调用 957 | Future.set\_result,这样就会调用与 Future 相关联的回调 958 | 959 | 960 | ## 前端知识之 jQuery、Ajax、JsonP等 961 | 962 | ### rgba()和opacity的透明效果有什么不同? 963 | 答案: rgba()和opacity都能实现透明效果,但最大的不同是opacity作用于元素,以及元素内的所有内容的透明度, 964 | 而rgba()只作用于元素的颜色或其背景色。(设置rgba透明的元素的子元素不会继承透明效果!) 965 | 966 | ### px和em的区别? 967 | px和em都是长度单位,区别是,px的值是固定的,指定是多少就是多少,计算比较容易。em得值不是固定的,并且em会继承父级元素的字体大小。 968 | 浏览器的默认字体高都是16px。所以未经调整的浏览器都符合: 1em=16px。那么12px=0.75em, 10px=0.625em。 969 | 970 | ### javascript:获取所有的checkbox? 971 | ```javascript 972 | var domList = document.getElementsByTagName(‘input’) 973 | // checkbox属于input,所以通过getElementsByTagName即标签名获取所有的input数组,包含文本框text,单选按钮radio,复选框checkbox等等 974 | var checkBoxList = []; // 定义一个存储checkbox的空数组 975 | var len = domList.length;  //缓存到局部变量 // 第一步获取的数组的长度 976 | while (len--) {  //使用while的效率会比for循环更高 // 开始循环判断 977 |   if (domList[len].type == ‘checkbox’) { // 如果类型为checkbox即为题目所需的复选框 978 |   checkBoxList.push(domList[len]); // 就把那个元素加入到上面定义的数组中 979 |   } 980 | } 981 | ``` 982 | 983 | 用js实现随机选取10–100之间的10个且不重复的数字,存入一个数组。 984 | ```javascript 985 | var randoms=[]; 986 | while (true) 987 | { 988 | var isExists = false; 989 | // 获取一个10–100范围的数 990 | var random = parseInt(10 + (90 - 10) * (Math.random())) 991 | // 判断当前随机数是否已经存在 992 | for (var i = 0; i < randoms.length; i++) { 993 | if (random === randoms[i]) { 994 | isExists = true; 995 | break; 996 | } 997 | } 998 | // 如果不存在,则添加进去 999 | if (!isExists) 1000 | randoms.push(random); 1001 | // 如果有10位随机数了,就跳出 1002 | if (randoms.length === 10) 1003 | break; 1004 | } 1005 | ``` 1006 | 1007 | ### window.onload与\$(document).ready()异同 1008 | 原生JS的`window.onload`与Jquery的`$(document).ready(function(){})`有什么不同?如何用原生JS实现Jq的ready方法? 1009 | `window.onload()`方法是必须等到页面内包括图片的所有元素加载完毕后才能执行。 1010 | `$(document).ready()`是DOM结构绘制完毕后就执行,不必等到加载完毕。`$(document).ready(function(){})`能够简写成`$(function(){})`。 1011 | 1012 | ### JS作用域 1013 | 1. JS以函数作为作用域 1014 | 2. 函数的作用域在未调用之前就已经创建 1015 | 3. 函数的作用域存在作用域链,并且也是在未调用之前创建 1016 | 4. 函数内局部变量提前声明 1017 | 1018 | ### 以下代码的输出是什么? 1019 | ```javascript 1020 | function t1(age){ 1021 | console.log(age); 1022 | var age = 27; 1023 | console.log(age); 1024 | function age(){}; 1025 | console.log(age); 1026 | } 1027 | t1(3) 1028 | // 答案 function age() 27 27 1029 | ``` 1030 | 1031 | ### 你为什么要使用jquery? 1032 | 因为jQuery是轻量级的框架,它有强大的选择器,出色的DOM操作的封装,有可靠的事件处理机制(jQuery在处理事件绑定的时候相当的可靠),完善的ajax(它的ajax封装的非常的好,不需要考虑复杂浏览器的兼容性和XMLHttpRequest对象的创建和使用的问题。) 出色的浏览器的兼容性。而且支持链式操作,隐式迭代。行为层和结构层的分离,还支持丰富的插件,jquery的文档也非常的丰富。 1033 | 1034 | ### 讲一下jquery有哪些选择器? 1035 | jQuery中的选择器大致分为:基本选择器,层次选择器,过滤选择器,表单选择器 1036 | 1037 | ### 你是如何使用jquery中的ajax的? 1038 | 如果是一些常规的ajax程序的话,使用`load()`,`$.get()`,`$.post()`,就可以搞定了,一般我会使用的是`$.post()` 方法。如果需要设定beforeSend(提交前回调函数),error(失败后处理),success(成功后处理)及complete(请求完成后处理)回调函数等,这个时候我会使用\$.ajax() 1039 | 1040 | ### `jquery中$.get()`提交和`$.post()`提交有区别吗? 1041 | `$.get()` 方法使用GET方法来进行异步请求的。`$.post()` 方法使用POST方法来进行异步请求的。 1042 | get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器的,这种传递是对用户不可见的。 1043 | get方式传输的数据大小不能超过2KB 而POST要大的多 1044 | GET 方式请求的数据会被浏览器缓存起来,因此有安全问题。 1045 | 1046 | ### 在jquery中你是如何去操作样式的? 1047 | addClass() 来追加样式 ,removeClass() 来删除样式,toggle() 来切换样式, css直接设置样式 1048 | style设置单个样式 1049 | 1050 | ### 你在jquery中使用过哪些插入节点的方法,它们的区别是什么? 1051 | append(),appendTo(),prepend(),prependTo(),after(),insertAfter(),before(),insertBefore() 大致可以分为 内部追加和外部追加append() 表式向每个元素内部追加内容。appendTo()表示 讲所有的元素追加到指定的元素中。例\$(A)appendTo(B) 是将A追加到B中下面的方法解释类似。 1052 | 1053 | 你使用过包裹节点的方法吗,包裹节点有方法有什么好处? 1054 | wrapAll(),wrap(), wrapInner()需要在文档中插入额外的结构化标记的时候可以使用这些包裹的方法应为它不会帛画原始文档的语义 1055 | 1056 | ### jquery中如何来获取或和设置属性? 1057 | jQuery中可以用attr()方法来获取和设置元素属性removeAttr() 方法来删除元素属性 1058 | 1059 | ### 如何来设置和获取HTML 和文本的值? 1060 | html()方法 类似于innerHTML属性 可以用来读取或者设置某个元素中的HTML内容 1061 | 注意:html() 可以用于xhtml文档 不能用于xml文档text() 类似于innerText属性 可以用来读取或设置某个元素中文本内容。val() 可以用来设置和获取元素的值 1062 | 1063 | ### jquery中有哪些方法可以遍历节点 1064 | children() 取得匹配元素的子元素集合,只考虑子元素不考虑后代元素 next() 取得匹配元素后面紧邻的同辈元素 1065 | prev() 取得匹配元素前面紧邻的同辈元素 1066 | siblings() 取得匹配元素前后的所有同辈元素 1067 | closest() 取得最近的匹配元素 1068 | find() 取得匹配元素中的元素集合 包括子代和后代 1069 | 1070 | ### radio单选组的第二个元素为当前选中值,该怎么去取? 1071 | ```javascript 1072 | $('input[name=items]').get(1).checked = true; 1073 | ``` 1074 | 1075 | ### 你知道jQuery中的事件冒泡吗,它是怎么执行的,何如来停止冒泡事件 1076 | 知道,事件冒泡是从里面的往外面开始触发。在jQuery中提供了stopPropagation()方法可以停止冒泡。 1077 | 1078 | ### 在jquery中你有没有编写过插件,插件有什么好处?它应该注意那些? 1079 | a) 插件的好处:对已有的一系列方法或函数的封装,以便在其他地方重新利用,方便后期维护和提高开发效率插件的分类:封装对象方法插件 、封装全局函数插件、选择器插件 1080 | b) 注意的地方: 1081 | 1. 插件的文件名推荐命名为`jquery.[插件名].js`,以免和其他的javaScript库插件混淆 1082 | 2. 所有的对象方法都应当附加到`jQuery.fn`对象上,而所有的全局函数都应当附加到jQuery对象本身上 1083 | 3. 插件应该返回一个jQuery对象,以保证插件的可链式操作 1084 | 4. 避免在插件内部使用\$作为jQuery对象的别名,而应使用完整的jQuery来表示,这样可以避免冲突或使用闭包来避免 1085 | 5. 所有的方法或函数插件,都应当一分好结尾,否则压缩的时候可能出现问题。在插件头部加上分号,这样可以避免他人的不规范代码给插件带来影响 1086 | 6. 在插件中通过`$.extent({})`封装全局函数,选择器插件,扩展已有的object对象通过`$.fn.extend({})`封装对象方法插件 1087 | 1088 | ## Ajax相关 1089 | 1090 | ### Ajax相关知识点 1091 | Iframe伪造Ajax请求 1092 | FormData对象以及Ajax文件上传 1093 | Iframe文件上传 1094 | JSONP实现AJax跨域 1095 | 1096 | ### XMLHttpRequest对象发送请求 1097 | Ajax和XMLHttpRequest 1098 | 从上面的解释中可以知道:ajax是一种技术方案,但并不是一种新技术。它依赖的是现有的CSS/HTML/Javascript,而其中最核心的依赖是浏览器提供的XMLHttpRequest对象,是这个对象使得浏览器可以发出HTTP请求与接收HTTP响应。 1099 | 所以我用一句话来总结两者的关系:我们使用XMLHttpRequest对象来发送一个Ajax请求。 1100 | 1101 | ### 什么是JSONP? 1102 | 由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过在页面动态创建script标签,通过通过src属性实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据数据传输。 1103 | 1104 | ### ajax与jsonp跨域请求的异同再做一些补充说明: 1105 | 1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装; 1106 | 2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加`