自我介绍:
公司模式什么样?
项目介绍:
团队有多少个人?
你觉得你的项目中的亮点是什么?
你项目中遇到的比较棘手的问题是什么?
你一般遇到的问题需要多久解决?
你自己做的模块中的数据库表是你自己设计的吗?一共几个表?哪几个表?
csrf是什么?跨域伪造请求,
正向代理和反向代理?
python的垃圾回收机制?
数据库引擎?
你认为什么是团队?团队制定目标完成任务
你认为你自己的特点是什么?
json.dumps()字典转json字符串,json.loads()json转字典
-
python内建数据类型有哪些? 可变不可变数据类型都是什么?
可变数据类型:当该数据类型对应的变量的值发生了变化时,如果它对应的内存地址不发生改变,那么这个数据类型就是 可变数据类型。
不可变数据类型:当该数据类型对应的变量的值发生了变化时,如果它对应的内存地址发生了改变,那么这个数据类型就是 不可变数据类型。
总结:可变数据类型更改值后,内存地址不发生改变。不可变数据类型更改值后,内存地址发生改变。
数据类型: 数值类型(整型--int,布尔型--bool),字符串--str,列表--list,元组--tuple,字典--dict,集合--set(不常用)
可变: list(列表)、dict(字典)、set(集合,不常用)
不可变: 数值类型(int、float、bool)、string(字符串)、tuple(元组)
-
字符串、字典、元组、列表常用方法?
字符串常用的是split、replace、join、find、strip、just
列表常用 pop 、append、 remove、 insert 、clear 、len 、sort、 reverse
字典常用 get、 index、 keys、 values、 update
-
从你项目中看出,你使用的是mysql,mysql的int数据类型都有哪些?从小到大说一下,各占多少字节?
(tinyint:1,smallint:2,mediumint:3,int:4,bigint:8)
-
mysql的索引结构
mysql的索引结构是b+树,然后b+树我觉得相对于b树来说优点在于他非叶子节点不存储数据,本身每个节点的空间是有限的,这样的话他每个节点能存储的节点数就更多,层级就更低。
然后因为它非叶子节点不存储数据,这样每次查询是一定要到叶子节点,查询就更稳定
然后还有就是它叶子节点是单链表连接的,这样天然有序。
-
CSRF是什么? XSS是什么? 跨域请求伪造 跨域脚本攻击
CSRF概念:CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解:
攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。 如下:其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户。
CSRF攻击攻击原理及过程如下:
1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
3. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
4. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
XSS跨域脚本攻击
原理
无需登录认证,核心原理就是向你的页面注入脚本。
1、反射型:发出请求时,XSS代码出现在URL中,作为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。
2、存储型:存储型XSS和反射型XSS的差别仅在于,提交的代码会存储在服务端(数据库,内存,文件系统等),下次请求目标页面时不用再提交XSS代码。(例如:常见的评论,在文本框中输入一段代码,那么就会存放在数据库当中,当再次加载的时候便会执行这样的代码)。
常见的场景
留言、评论、注册、登录等
攻击示例
CSS攻击
用户上传的style节点、script节点、iframe节点等,场景:比如用户在上传的过程中构建了一个style节点,里面写着body display:none !important,大家知道!important在CSS中的优先级最高,如果用户上传的里面真有这样的CSS的话,后果是什么,后果就是任何包含这个CSS文件的页面,用户看到的都是空白页面,因为body是隐藏的,攻击完成!
JavaScript攻击
新浪博客写一篇文章,同时偷偷插入一段script,然后发布,发布完成以后如果有人看了,那么我们插入的script就会执行,攻击代码中获取cookie(现在不常有了,个人信息一般会有手机号,邮箱等),接下来就会把查看着的cookie发送的攻击者的服务器。
alert(document.cookie) // 这段代码意思就是获取cookie,那么cookie中可能存在用户的敏感信息
防御
编码,对用户的输入不能保持原样,要进一步处理,对用户输入的数据进行HTML Entity编码(十进制或转义字符);
正则过滤,要把不安全或不合理的内容过滤掉,比如移除用户上传的DOM属性,如onerror、onclick、onmousdown、替换script为''等,除了在你的业务中有特殊需求的其它事件都要过滤掉;我们只需要把script的<>尖括号转换了就可以了, 让它形成不了JS的代码块,无法执行就可以了。
后端也可以替换;前端替换会影响性能
// 安装一个插件
cnpm i xss -D
// 使用,在需要的地方引入
const xss = require('xss')
// xss其实是一个函数,只需要把创建博客时候的title及content包起来就可以了
const title = xss(blogData.title)
// 这样的话title里面的JS就被我们转义了
// 转义过后先显示在前端页面上就是转义后的了,需要前端再次转回去,这个交给前端来做,合格的后端不可能在数据库存储具有攻击可能性的代码。
-
正向代理 反向代理?
web 开发中,部署方式大致类似。简单来说,使用 Nginx 主要是为了实现分流、转发、负载均衡,
以及分担服务器的压力。Nginx 部署简单,内存消耗少,成本低。Nginx 既可以做正向代理,也可以
做反向代理。
正向代理:
请求经过代理服务器从局域网发出,然后到达互联网上的服务器。
特点:服务端并不知道真正的客户端是谁。
反向代理:
请求从互联网发出,先进入代理服务器,再转发给局域网内的服务器。
特点:客户端并不知道真正的服务端是谁。
区别:
正向代理的对象是客户端。反向代理的对象是服务端。
- 正向代理
先搭建一个属于自己的代理服务器
1、用户发送请求到自己的代理服务器
2、自己的代理服务器发送请求到服务器
3、服务器将数据返回到自己的代理服务器
4、自己的代理服务器再将数据返回给用
正向代理有什么用为什么要这么做:
作用:正向代理隐藏了用户,用户的请求被代理服务器接收代替,到了服务器,服务器并不知道用户是谁。
用途:当你用浏览器访问国外的网站时,被block(拒绝)时,你可以在国外搭建一个代理服务器,这样就可以正常访问了(只是举一个列子)
- 反向代理
1、用户发送请求到服务器(访问的其实是反向代理服务器,但用户不知道)
2、反向代理服务器发送请求到真正的服务器
3、真正的服务器将数据返回给反向代理服务器
4、反向代理服务器再将数据返回给用户
反向代理有什么用为什么要这么做:
作用:用户请求过多,服务器会有一个处理的极限。所以使用反向代理服务器接受请求,再用均衡负载将请求分布给多个真实的服务器。既能提高效率还有一定的安全性。
用途:如果不采用代理,用户的IP、端口号直接暴露在Internet(尽管地址转换NAT),外部主机依然可以根据IP、端口号来开采主机安全漏洞,所以在企业网,一般都是采用代理服务器访问互联网。
正向代理与反向代理最简单的区别:
正向代理隐藏的是用户,反向代理隐藏的是服务器
-
垃圾回收机制?
1. 引用计数
引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。当 Python 的某
个对象的引用计数降为 0 时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如
某个新建对象,它被分配给某个引用,对象的引用计数变为 1。如果引用被删除,对象的引用计数为 0,
那么该对象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了。
2. 标记清除
如果两个对象的引用计数都为 1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被
回收的,也就是说,它们的引用计数虽然表现为非 0,但实际上有效的引用计数为 0。所以先将循环引
用摘掉,就会得出这两个对象的有效计数。
3. 分代回收
从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统
中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾
回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额
外操作。
-
MySQL引擎?
常用的存储引擎有以下:
Innodb引擎:Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。
MyIASM引擎(原本Mysql的默认引擎):不提供事务的支持,也不支持行级锁和外键。
MEMORY引擎:所有的数据都在内存中,数据的处理速度快,但是安全性不高。
InnoDB引擎的4大特性
插入缓冲(insert buffer)
二次写(double write)
自适应哈希索引(ahi)
预读(read ahead)
存储引擎选择
如果没有特别的需求,使用默认的Innodb即可。
MyISAM:以读写插入为主的应用程序,比如博客系统、新闻门户网站。
Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,支持事务和外键。比如OA自动化办公系统。
innodb引擎 Memory引擎 Merge引擎 MyISAM存储引擎
innodb引擎一大特点就是支持外键。 内存和空间大 支持事务.
-
数据库三大范式是什么
第一范式(1NF):字段具有原子性,不可再分。(所有关系型数据库系 统都满足第一范式数据库表中的字段都是单一属性的,不可再分)
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。要求数据库表中的每 个实例或行必须可以被惟一地区分。通常需要为表加上一个列,以存储 各个实例的惟一标识。这个惟一属性列被称为主关键字或主键。
满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关 键字信息。
所以第三范式具有如下特征:
每一列只有一个 值
每一行都能区分。
每一个表都不包含其他表已经包含 的非主关键字信息
-
Celery 命令 三步骤?
Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成。
1.消息中间件
Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis, MongoDB (experimental), Amazon SQS (experimental),CouchDB (experimental), SQLAlchemy (experimental),Django ORM (experimental), IronMQ
2.任务执行单元
Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。
3.任务结果存储
Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, redis,memcached, mongodb,SQLAlchemy, Django ORM,Apache Cassandra, IronCache 等。
启动命令:
celery -A tasks worker --loglevel=info
-
Radis 有哪几种数据类型?
-
String:字符串
-
hash:散列、hash表
-
list:列表
-
set:无序集合
-
zset:有序集合
-
Linux基本命令 10个?
ls , ll -la , cd , cd .. , cd ~ , cp , mv , mkdir , touch , ll , tree , pwd https://www.cnblogs.com/fnlingnzb-learner/p/5831284.html
-
深拷贝 浅拷贝?
1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用 ,
2.深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”, 在改变新的数组(对象)的时候,不改变原数组(对象)
3.浅拷贝可以使用列表自带的copy()函数(如list.copy()),或者使用copy模块的copy()函数。深拷贝只能使用copy模块的deepcopy(),所以使用前要导入:from copy import deepcopy
4.如果拷贝的对象里的元素只有值,没有引用,那浅拷贝和深拷贝没有差别,都会将原有对象复制一份,产生一个新对象,对新对象里的值进行修改不会影响原有对象,新对象和原对象完全分离开。
-
Http协议 列举Http请求方法? 列举Http常用请求头?列举Http状态码? Django请求生命周期? 什么是wsgi
-
请求:
-
请求方法
-
请求地址
-
请求内容
-
请求头
-
请求环境
-
响应:
-
状态吗
-
响应数据
-
响应头
- wsgi的作用就是将上面数据在server端和python程序间进行传递 它是一个标准 一个需要遵从的规范 才能正常工作
-
Django 中间件作用?应用?
中间件是服务器端与应用程序的一个中间层,它将个管道一样。将接受到的请求进行一些处理。然后传递到客户端 然后把客户端处理的结果再返回
它的应用场景是:
-
根据url把请求给到不同的客户端程序
-
允许多个客户端
-
负载均衡和远程处理
-
应答的过滤处理
-
Django请求周期?
Django的请求生命周期是指:当用户在浏览器上输入url到用户看到网页的这个时间段内,Django后台所发生的事情。
(1)过程描述
第一步:浏览器发起请求
第二步:WSGI创建socket服务端,接收请求(Httprequest)
第三步:中间件处理请求
第四步:url路由,根据当前请求的URL找到视图函数
第五步:view视图,进行业务处理(ORM处理数据,从数据库取到数据返回给view视图;view视图将数据渲染到template模板;将数据返回)
第六步:中间件处理响应
第七步:WSGI返回响应(HttpResponse)
第八步:浏览器渲染
(2)过程图解
-
MySQL索引?
索引使用场景(重点)
where
上图中,根据id查询记录,因为id字段仅建立了主键索引,因此此SQL执行可选的索引只有主键索引,如果有多个,最终会选一个较优的作为检索的依据。
-- 增加一个没有建立索引的字段
alter table innodb1 add sex char(1);
-- 按sex检索时可选的索引为null
EXPLAIN SELECT * from innodb1 where sex='男';
可以尝试在一个字段未建立索引时,根据该字段查询的效率,然后对该字段建立索引(alter table 表名 add index(字段名)),同样的SQL执行的效率,你会发现查询效率会有明显的提升(数据量越大越明显)。
order by
当我们使用order by将查询结果按照某个字段排序时,如果该字段没有建立索引,那么执行计划会将查询出的所有数据使用外部排序(将数据从硬盘分批读取到内存使用内部排序,最后合并排序结果),这个操作是很影响性能的,因为需要将查询涉及到的所有数据从磁盘中读到内存(如果单条数据过大或者数据量过多都会降低效率),更无论读到内存之后的排序了。但是如果我们对该字段建立索引alter table 表名 add index(字段名),那么由于索引本身是有序的,因此直接按照索引的顺序和映射关系逐条取出数据即可。而且如果分页的,那么只用取出索引表某个范围内的索引对应的数据,而不用像上述那取出所有数据进行排序再返回某个范围内的数据。(从磁盘取数据是最影响性能的)
join
对join语句匹配关系(on)涉及的字段建立索引能够提高效率
索引覆盖
如果要查询的字段都建立过索引,那么引擎会直接在索引表中查询而不会访问原始数据(否则只要有一个字段没有建立索引就会做全表扫描),这叫索引覆盖。因此我们需要尽可能的在select后只写必要的查询字段,以增加索引覆盖的几率。
这里值得注意的是不要想着为每个字段建立索引,因为优先使用索引的优势就在于其体积小。
索引算法有哪些?
BTree算法
BTree是最常用的mysql数据库索引算法,也是mysql默认的算法。因为它不仅可以被用在=,>,>=,<,<=和between这些比较操作符上,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量, 例如:
-- 只要它的查询条件是一个不以通配符开头的常量
select * from user where name like 'jack%';
-- 如果一通配符开头,或者没有使用常量,则不会使用索引,例如:
select * from user where name like '%jack';
Hash算法
Hash Hash索引只能用于对等比较,例如=,<=>(相当于=)操作符。由于是一次定位数据,不像BTree索引需要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引。
-
百万级别或以上的数据如何删除
关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。
1.所以我们想要删除百万数据的时候可以先删除索引(此时大概耗时三分多钟)
2.然后删除其中无用数据(此过程需要不到两分钟)
3.删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。
4.与之前的直接删除绝对是要快速很多,更别说万一删除中断,一切删除会回滚。那更是坑了。
-
多线程 多进程区别?
进程是资源分配的最小单位,线程是CPU调度的最小单位
-
并发
并行(parallel)是指同一时刻,两个或两个以上时间同时发生。
并发(parallel)是指同一时间间隔(同一段时间),两个或两个以上时间同时发生。
-
悲观锁和乐观锁是什么?
使用场景:
你银行卡现在100块,
A地花了10块,然后A地停电,会有延迟扣款
然后你的公司给你同时发了200工资,
如果公司先査你的钱100,同时A地查也是查到100
你公司先update了,你现在300,
然后A地扣除,你现在就是90块了.
这个地方乐观锁和悲观锁都可以选择作为使用.
乐观锁就是A地要更新的时候先回去查一下有没有被B地改了.
悲观锁就是A地读取数据的时候,直接把银行卡里的数据锁死,禁止除了自己以外的人写入.
如果是在django中,那么悲观锁的实现方式如下[1]:
obj = 模型类名.objects.select_for_update().get(id=1)
乐观锁实现案例[1]:
from django.shortcuts import render from django.http import JsonResponse from django.views.generic import View from django.db import transaction from 应用名.models import GoodsSKU # 类视图 (并发,乐观锁)
class MyView(View): @transaction.atomic def post(self, request): '''订单创建''' count = 3 # 订购3件商品
# 设置事务保存点
s1 = transaction.savepoint() # 乐观锁,最多尝试5次
for i in range(5): # 查询商品的信息(库存)
try: sku = GoodsSKU.objects.get(id=1) except: # 商品不存在
transaction.savepoint_rollback(s1) return JsonResponse({'res': 1, 'errmsg': '商品不存在'}) # 判断商品的库存
if count > sku.stock: transaction.savepoint_rollback(s1) return JsonResponse({'res': 2, 'errmsg': '商品库存不足'}) # 更新商品的库存和销量
orgin_stock = sku.stock # 原库存 (数据库隔离级别必须是Read Committed;如果是Repeatable Read,那么多次尝试读取的原库存都是一样的,读不到其他线程提交更新后的数据。)
new_stock = orgin_stock - count # 更新后的库存
new_sales = sku.sales + count # 更新后的销量
# update 商品表 set stock=new_stock, sales=new_sales where id=1 and stock = orgin_stock
# 通过where子句中的条件判断库存是否进行了修改。(并发,乐观锁)
# 返回受影响的行数
res = GoodsSKU.objects.filter(id=1, stock=orgin_stock).update(stock=new_stock, sales=new_sales) if res == 0: # 如果修改失败
if i == 4: # 如果尝试5次都失败
transaction.savepoint_rollback(s1) return JsonResponse({'res': 3, 'errmsg': '下单失败'}) continue # 再次尝试
# 否则更新成功
# 跳出尝试循环
break
# 提交事务
transaction.savepoint_commit(s1) # 返回应答
return JsonResponse({'res': 4, 'message': '创建成功'}
-
数据库查询,查询最新的10条数据?
desc limit 10
-
你知道生成器和迭代器的区别吗?都用在什么地方?
(1)生成器:
生成器本质上就是一个函数,它记住了上一次返回时在函数体中的位置。
对生成器函数的第二次(或第n次)调用,跳转到函数上一次挂起的位置。
而且记录了程序执行的上下文。生成器不仅“记住”了它的数据状态,生成还记住了程序执行的位置。
生成器函数:------------------------------------------------------------------
# 菲波那切数列
def Fib(max): n, a, b = 0, 0, 1
while n < max: yield b a, b = b, a + b n = n + 1
return '亲!没有数据了...'
# 调用方法,生成出10个数来
f=Fib(10) # 使用一个循环捕获最后return 返回的值,保存在异常StopIteration的value中
while True: try: x=next(f) print("f:",x) except StopIteration as e: print("生成器最后的返回值是:",e.value) break 生成器表达式:-----------------------------------------------------------------
# 一个列表
xiaoke=[2,3,4,5] # 生成器generator,类似于list,但是是把[]改为()
gen=(a for a in xiaoke) for i in gen: print(i) #结果是:
2
3
4
5
# 为什么要使用生成器?因为效率。
# 使用生成器表达式取代列表推导式可以同时节省 cpu 和 内存(RAM)。
# 如果你构造一个列表(list)的目的仅仅是传递给别的函数,
# 比如 传递给tuple()或者set(), 那就用生成器表达式替代吧!
# 本案例是直接把列表转化为元组
kk=tuple(a for a in xiaoke) print(kk) #结果是:
(2, 3, 4, 5)
# python内置的一些函数,可以识别这是生成器表达式,外面有一对小括号,就是生成器
result1=sum(a for a in range(3)) print(result1)
# 列表推导式
result2=sum([a for a in range(3)]) print(result2)
(2)迭代器
迭代器是一种支持next()操作的对象。它包含了一组元素,当执行next()操作时,返回其中一个元素。当所有元素都被返回后,再执行next()报异常—StopIteration生成器一定是可迭代的,也一定是迭代器对象.
class Fib(object): def __init__(self, max): super(Fib, self).__init__() self.max = max def __iter__(self): self.a = 0 self.b = 1
return self def __next__(self): fib = self.a if fib > self.max: raise StopIteration self.a, self.b = self.b, self.a + self.b return fib # 定义一个main函数,循环遍历每一个菲波那切数
def main(): # 20以内的数
fib = Fib(20) for i in fib: print(i) # 测试
if __name__ == '__main__': main()
(3)区别:
-
有iter()和next()魔法方法的对象,都是迭代器(可以为你的类添加迭代器行为);
-
生成器是一个用于创建迭代器的工具,它们的写法类似标准的函数,但当它们要返回数据时会使用yield语句。每次对生成器调用next()时,它会从上次离开位置恢复执行(它会记住上次执行语句时的所有数据值)。
①生成器是生成元素的,迭代器是访问集合元素的一中方式
②迭代输出生成器的内容
③迭代器是一种支持next()操作的对象
④迭代器(iterator):其中iterator对象表示的是一个数据流,可以把它看做一个有序序列,但我们不能提前知道序列的长度,只有通过nex()函数实现需要计算的下一个数据。可以看做生成器的一个子集。
-
函数闭包的理解?
是指函数中嵌套函数 且外层函数的返回值也是函数 闭包中需要注意的是变量的作用域,内层函数使用外层函数的值需要加nolocal 使用全局变量的值需要加global
-
什么是装饰器?应用场景?
一句话解释什么样的语言能够用装饰器?
函数可以作为参数传递的语言,可以使用装饰器。
装饰器的特点是返回值和参数都是函数
装饰器的目的就是对已封装函数进行操作,为其加上新的功能或一系列运算 。 在django中有middleware中间件,它其实就是高级的装饰器用法,
def outside(func): def inside(str): func(str) #函数体 return inside @outside def hello(str): #函数体 hello(str)
-
GIL?
GIL 全局解释器锁
-
单个进程假如有多个线程运行, 一个线程在运行python程序的时候就会霸占python解释器(即加了一把锁GIL) 使其它线程无法运行,等该进程运行结束后其他进程才能运行;
如果线程运行中遇到耗时操作,则解释器锁解开,使其它线程运行,所以 在多线程中,线程的运行是有先后顺序的,并不是同时进行;
-
多个进程中因为每个进程都能被系统分配资源,等于是每个进程都有一个python解释器,所以多进程可以实现多个进程的同时使用,缺点是进程系统资源开销大;
-
什么是死锁?怎么解决?
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。
常见的解决死锁的方法
1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;
如果业务处理不好可以用分布式事务锁或者使用乐观锁
-
数据库的乐观锁和悲观锁是什么?怎么实现的?
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐一般会使用版本号机制或CAS算法实现。
两种锁的使用场景
从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
-
数据库锁?
由于数据库是多用户共享资源,所以需要处理并发问题,而数据库锁的机制就是为了处理这一问题,当出现并发的时候,如果不做控制就会出现各种问题 比如脏数据。修改丢失等 所有数据库并发需要事务来控制,事务并发问题需要数据库锁来控制
事务四个特性。持久型 原子性 一致性 隔离性
数据库锁有 乐观锁 悲观锁 死锁。活锁 行锁 表锁 页级锁 排它锁又称为写锁。共享锁又称为读锁
-
大表数据查询,怎么优化
-
优化shema、sql语句+索引;
-
第二加缓存,memcached, redis;
-
主从复制,读写分离;
-
垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
-
水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;