自我介紹:
公司模式什么樣?
項目介紹:
團隊有多少個人?
你覺得你的項目中的亮點是什么?
你項目中遇到的比較棘手的問題是什么?
你一般遇到的問題需要多久解決?
你自己做的模塊中的數據庫表是你自己設計的嗎?一共幾個表?哪幾個表?
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,將數據定位到限定的表上去查,而不是掃描全部的表;
