多有參考
全棧修煉手冊
Python常見的170道面試題
關(guān)于python的面試題
python語言特性
-
python2 和 python3 的區(qū)別?
- print在python3中是函數(shù)必須加括號唧龄,在python2中為class祠够。
- python2只能夠默認(rèn)的字符串類型是ASCII冗尤,python3中默認(rèn)字符串類型是Unicode旋炒。
- python2中
/
的結(jié)果是整型python3中的是浮點(diǎn)型 - python2中使用xrange掌测,python3中使用range乖阵。
xrange生成一個(gè)list對象旅择,range生成一個(gè)range對象(可迭代惭笑,但不是迭代器)
python3中的基本數(shù)據(jù)類型
字符串(string)、數(shù)字(digit)生真、列表(list)沉噩、元組(tuple)、集合(sets)柱蟀、字典(dictionary)川蒙。-
python3常用方法函數(shù)
- python內(nèi)置結(jié)構(gòu)時(shí)間復(fù)雜度
- 字符串內(nèi)建函數(shù)
- python內(nèi)置函數(shù)
- python中的拷貝(引用和copy()、deepcopy()的區(qū)別)
- 對于不可變對象沒有意義
- 淺拷貝構(gòu)造一個(gè)新的復(fù)合對象长已,然后(盡可能)將對它的引用插入到原始對象中畜眨。
- 深拷貝構(gòu)造一個(gè)新的復(fù)合對象,然后遞歸地將復(fù)制對象插入到原始對象中找到的對象中术瓮。
- 了解enumerate嘛康聂?
enumerate可以在迭代一個(gè)對象的時(shí)候同時(shí)獲取當(dāng)前對象的索引和值。for index, value in enumerate([a,b,c,d])
- isinstance 作用以及應(yīng)用場景胞四?
判斷一個(gè)對象是否是另一個(gè)對象的子類
print(isinstance(True,int))
-
lambda
表達(dá)式格式以及應(yīng)用場景恬汁?
匿名函數(shù)lambda x: x表達(dá)式
按照字典的值排序 d = {'a':2,'b':1,'c':3} print(dict(sorted(d.items(), key=lambda x:x[1]))) # {'b':1,'a':2,'c':3}
-
map()
函數(shù)接收兩個(gè)參數(shù),一個(gè)是函數(shù)撬讽,一個(gè)是Iterable蕊连,map將傳入的函數(shù)依次作用到序列的每個(gè)元素,并把結(jié)果作為新的Iterator返回游昼。
推薦使用列表推導(dǎo)式def f(x): return x * x r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) list(r) #[1, 4, 9, 16, 25, 36, 49, 64, 81] 列表推導(dǎo)式 [i*i for i in range(1,10)]
-
reduce()
把一個(gè)函數(shù)作用在一個(gè)序列[x1, x2, x3, ...]上甘苍,這個(gè)函數(shù)必須接收兩個(gè)參數(shù),reduce把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算烘豌,其效果就是:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
把序列[1, 3, 5, 7, 9]變換成整數(shù)13579载庭,reduce就可以派上用場: from functools import reduce def fn(x, y): return x * 10 + y reduce(fn, [1, 3, 5, 7, 9]) #13579
-
filter()
也接收一個(gè)函數(shù)和一個(gè)序列。和map()不同的是廊佩,filter()把傳入的函數(shù)依次作用于每個(gè)元素囚聚,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素。
同樣推薦使用列表推導(dǎo)式def is_odd(n): return n % 2 == 1 list(filter(is_odd, [1, 4, 9, 16, 25])) # 結(jié)果: [1, 9, 25] [i for i in [j*j for j in range(1,6)] if i%2 == 1]
-
zip()
函數(shù)用于將可迭代的對象作為參數(shù)标锄,將對象中對應(yīng)的元素打包成一個(gè)個(gè)元組顽铸,然后返回由這些元組組成的對象,這樣做的好處是節(jié)約了不少的內(nèi)存料皇。
我們可以使用 list() 轉(zhuǎn)換來輸出列表谓松。
如果各個(gè)迭代器的元素個(gè)數(shù)不一致,則返回列表長度與最短的對象相同践剂,利用 * 號操作符鬼譬,可以將元組解壓為列表。#把元組 ("a","b") 和元組 (1,2)逊脯,變?yōu)樽值?{"a":1,"b":2} a = ("a", "b") b = (1, 2) print(dict(zip(a, b)))
#交換字典的鍵和值 s = {"A":1,"B":2} #方法一: dict_new = {value:key for key优质,value in s.items()} # 方法二: new_s= dict(zip(s.values(),s.keys()))
什么是閉包军洼?
當(dāng)一個(gè)內(nèi)嵌函數(shù)引用其外部作作用域的變量,我們就會(huì)得到一個(gè)閉包. 總結(jié)一下,創(chuàng)建一個(gè)閉包必須滿足以下幾點(diǎn):
必須有一個(gè)內(nèi)嵌函數(shù)
內(nèi)嵌函數(shù)必須引用外部函數(shù)中的變量
外部函數(shù)的返回值必須是內(nèi)嵌函數(shù)
裝飾器本質(zhì)就是一個(gè)閉包-
什么是裝飾器巩螃?
裝飾器就是一個(gè)函數(shù),它可以在不需要做任何代碼變動(dòng)的前提下給一個(gè)函數(shù)增加額外功能匕争,啟動(dòng)裝飾的效果牺六。比如插入日志def log(func): def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper @log def now(): print("2019.8.20") >>> now() call now(): 2019.8.20 但是now.__name__變成了'wrapper',因?yàn)槲覀兎祷氐木褪莣rapper汗捡,不過python早都考慮到了淑际,完整實(shí)現(xiàn)如下: import functools def log(func): @functools.wraps(func) def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper
-
python解包?
解包在英文里叫做 Unpacking扇住,就是將容器里面的元素逐個(gè)取出來a,b,c = [1,2,3]
這個(gè)過程就是解包春缕,python中解包是自動(dòng)完成的.-
代碼中經(jīng)常遇到的*args, **kwargs 含義及用法。
在函數(shù)定義中使用 args 和*kwargs 傳遞可變長參數(shù)艘蹋。 *args 用來將參數(shù)打包成 tuple 給函數(shù)體調(diào)用锄贼。 **kwargs 打包關(guān)鍵字參數(shù)成 dict 給函數(shù)體調(diào)用。
合并兩個(gè)字典 a = {"A":1,"B":2} b = {"C":3,"D":4} # a.update(b) print({**a,**b})
n = [1,2,3,4] a,*b,c = n a,b,c #1,[2,3],[3]
- 自動(dòng)解包支持一切可迭代對象
- 可以用星號操作使等號左邊的變量個(gè)數(shù)少于右邊的元素個(gè)數(shù)
1.函數(shù)調(diào)用時(shí)女阀,可以使用* 或**解包可迭代對象
-
-
python函數(shù)傳參宅荤?
python中傳的是對象的引用屑迂。
默認(rèn)參數(shù)只初始化一次且必須指向不變對象from datetime import datetime def test(t=datetime.today()): print t if __name__ == "__main__": test() test() 兩次調(diào)用輸出為同一個(gè)值 建議常用下面一種方式 from datetime import datetime def test2(t = None): if t is None: t = datetime.today() print t if __name__ == "__main__": test() test()
def func(item, item_list=[]): item_lsit.append(item) print(item_lsit) func('xiaomi') #[xiaomi] func('iphone',item_list=['xiaomi','huawei'])#[xiaomi,huawei,iphone] func('vivo')#[xiaomi,vivo] 第一次初始化def時(shí)會(huì)生成可變對象的內(nèi)存地址,然后將這個(gè)默認(rèn)參數(shù)item_list與內(nèi)存地址綁定冯键。 在后面的調(diào)用中惹盼,如果指定了新的默認(rèn)值,就會(huì)將原來的默認(rèn)值覆蓋掉惫确,如果沒有指認(rèn)的話手报,就會(huì)用原來的默認(rèn)值。
-
什么是列表推導(dǎo)式改化?字典推導(dǎo)式呢掩蛤?集合推導(dǎo)式?
[x for x in range(10)]
#[[1,2],[3,4],[5,6]] 一行代碼展開該列表陈肛,得出 [1,2,3,4,5,6] l = [[1,2],[3,4],[5,6]] x=[j for i in l for j in i] print(x)
d = {key: value for (key, value) in iterable}
# 把字典的key和value調(diào)換 d = {'a':'1', 'b':'2'} print({v:k for k,v in d.items()})
#如何把元組 ("a","b") 和元組 (1,2)揍鸟,變?yōu)樽值?{"a":1,"b":2} a = ("a", "b") b = (1, 2) print(dict(zip(a, b)))
-
squared = {x**2 for x in [1, 1, 2]}
與列表推導(dǎo)式類似,唯一區(qū)別在于它使用大括號
什么是迭代器句旱?
迭代器對象從集合的第一個(gè)元素開始訪問蜈亩,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會(huì)后退前翎。
迭代器有兩個(gè)基本的方法:iter(可迭代對象) 和 next(迭代器)-
如何創(chuàng)建一個(gè)迭代器稚配?
把一個(gè)類作為迭代器使用需要在類中實(shí)現(xiàn)__iter__()
和__next__()
__iter__()
方法返回一個(gè)特殊的迭代器對象, 這個(gè)迭代器對象實(shí)現(xiàn)了 next() 方法并通過 StopIteration 異常標(biāo)識(shí)迭代的完成港华。
__next__()
方法會(huì)返回下一個(gè)迭代器對象道川。class MyNumbers: def __iter__(self): self.a = 1 return self def __next__(self): if self.a <= 20: x = self.a self.a += 1 return x else: raise StopIteration myclass = MyNumbers() myiter = iter(myclass) for x in myiter: print(x)#1-20
-
什么是生成器?
- 在 Python 中立宜,使用了 yield 的函數(shù)被稱為生成器(generator)冒萄。
- 跟普通函數(shù)不同的是,生成器是一個(gè)返回迭代器的函數(shù)橙数,只能用于迭代操作尊流,更簡單點(diǎn)理解生成器就是一個(gè)迭代器。
- 在調(diào)用生成器運(yùn)行的過程中灯帮,每次遇到 yield 時(shí)函數(shù)會(huì)暫停并保存當(dāng)前所有的運(yùn)行信息崖技,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時(shí)從當(dāng)前位置繼續(xù)運(yùn)行。
- 調(diào)用一個(gè)生成器函數(shù)钟哥,返回的是一個(gè)迭代器對象迎献。
#請將 [i for i in range(3)] 改成生成器 (i for i in range(3)) 不同的是生成式不必創(chuàng)建完整的list,從而節(jié)省大量的空間
單下劃線和雙下劃線腻贰?
__foo__
: 一種約定,Python內(nèi)部的名字,用來區(qū)別其他用戶自定義的命名,以防沖突吁恍,就是例如__init__()
,__call__()
這些特殊方法
_foo
:一種約定,用來指定變量私有.程序員用來指定私有變量的一種方式.不能用from module import * 導(dǎo)入,其他方面和公有一樣訪問;
__foo:
這個(gè)有真正的意義:解析器用classname__foo來代替這個(gè)名字,以區(qū)別和其他類相同的命名,它無法直接像公有成員一樣隨便訪問,通過對象名.類名__xxx這樣的方式可以訪問.hasattr()冀瓦、getattr()伴奥、setattr() 、delattr()的用法(python中的反射)翼闽?
配合dir()獲取一個(gè)對象的所有屬性和方法
hasattr(obj,'attr')可以判斷一個(gè)對象是否含有某個(gè)屬性拾徙,getattr(obj,'attr',default) 可以充當(dāng) get 獲取對象屬性的作用相當(dāng)于obj.attr
。 setattr(obj,'attr','abc') 可以充當(dāng) obj.attr = "abc"的賦值操作,delattr(obj,'attr')相當(dāng)于del obj.attr魔法方法以及用途肄程。
init
類的初始化方法
new
對象實(shí)例化時(shí)第一個(gè)調(diào)用的方法
slots
動(dòng)態(tài)的給類添加屬性和方法
str
友好打印
repr
程序友好打印
call
對實(shí)例進(jìn)行調(diào)用實(shí)例名()
property
使實(shí)例方法可以像實(shí)例屬性一樣訪問
使用時(shí)只需要在對應(yīng)的方法上加@property
同時(shí)會(huì)生成@方法名.setter
、@方法名.deleter
修飾的方法可用來升級取代getattr
和setattr
python中的元類
這個(gè)不常用选浑,但是像ORM中還是需要的蓝厌,比如在ORM中想定義一個(gè)父類而不是生成一張表就要用元類。-
@staticmethod和@classmethod
- 相同之處:@staticmethod和@classmethod都可以直接類名.方法名()來調(diào)用古徒,不用實(shí)例化一個(gè)類拓提。
- @staticmethod 經(jīng)常有一些和類相關(guān)的功能但是運(yùn)行時(shí)又不需要實(shí)例和類參數(shù)的參與。
@classmethod 需要在類中運(yùn)行而不再實(shí)例中運(yùn)行的方法
-
類變量和實(shí)例變量
- 類變量:是可在類的所有實(shí)例之間共享的值(也就是說隧膘,它們不是單獨(dú)分配給每個(gè)實(shí)例的)代态。例如下例中,num_of_instance 就是類變量疹吃,用于跟蹤存在著多少個(gè)Test 的實(shí)例蹦疑。
- 實(shí)例變量:實(shí)例化之后,每個(gè)實(shí)例單獨(dú)擁有的變量萨驶。
-
with的作用歉摧?
with 提供了一種機(jī)制,可以在進(jìn)入和退出(無論正常退出腔呜,還是異常退出)某個(gè)語句塊時(shí)叁温,自動(dòng)執(zhí)行自定義的代碼。
對這個(gè)機(jī)制的封裝核畴,叫做上下文管理器膝但。with 是對上下文管理器的調(diào)用。一般訪問文件時(shí)的操作 f = open( 'test.txt', 'r') try : data = f.read() finally: f.close() 同樣的語句我們可以用with來實(shí)現(xiàn) with open('test.txt', 'r') as f: data = f.read()
-
如何實(shí)現(xiàn)上下文管理器谤草?
在python中實(shí)現(xiàn)了__enter__()
和__exit__()
方法對象就可以稱為上下文管理器class File(object): def __init__(self, file_name, file_model): self.file_name = file_name self.file_model = file_model def __enter__(self): self.f = open(self.file_name, self.model) return self.f def __exit__(self): self.f.close() with File('test.txt', 'r') as f: data = f.read()
-
w跟束、a+、wb文件寫入模式的區(qū)別
- w打開一個(gè)文件用與寫入,如果該文件存在則會(huì)將原有的文件覆蓋,如果該文件不存在,則會(huì)創(chuàng)建一個(gè)新文件
- wb以二進(jìn)制的格式去寫入數(shù)據(jù),如果該文件已經(jīng)存在則會(huì)將原有的文件覆蓋,如果該文件件不存在,則會(huì)創(chuàng)建一個(gè)新文件
- a+ 打開一個(gè)文件,用于讀寫,如果該文件已經(jīng)存在,文件的指針將會(huì)放在文件的結(jié)尾位置,新的內(nèi)容會(huì)被寫入到已有內(nèi)容的后面丑孩。如果該文件不存在,則會(huì)創(chuàng)建新文件用于讀寫
-
read泳炉、readline、readlines的區(qū)別嚎杨?
- read 讀取整個(gè)文件
- readline 讀取下一行,使用生成器方法
- readlines 讀取整個(gè)文件到一個(gè)迭代器以供我們遍歷
鴨子類型
“當(dāng)看到一只鳥走起來像鴨子花鹅、游泳起來像鴨子、叫起來也像鴨子枫浙,那么這只鳥就可以被稱為鴨子刨肃」潘”
我們并不關(guān)心對象是什么類型,到底是不是鴨子真友,只關(guān)心行為黄痪。
比如在python中,有很多file-like的東西盔然,比如StringIO,GzipFile,socket桅打。它們有很多相同的方法,我們把它們當(dāng)作文件使用愈案。
又比如list.extend()方法中,我們并不關(guān)心它的參數(shù)是不是list,只要它是可迭代的,所以它的參數(shù)可以是list/tuple/dict/字符串/生成器等.-
單例模式
單例模式是一種常用的軟件設(shè)計(jì)模式挺尾。在它的核心結(jié)構(gòu)中只包含一個(gè)被稱為單例類的特殊類。通過單例模式可以保證系統(tǒng)中一個(gè)類只有一個(gè)實(shí)例而且該實(shí)例易于外界訪問站绪,從而方便對實(shí)例個(gè)數(shù)的控制并節(jié)約系統(tǒng)資源遭铺。如果希望在系統(tǒng)中某個(gè)類的對象只能存在一個(gè),單例模式是最好的解決方案恢准。
__new__()
在__init__()
之前被調(diào)用魂挂,用于生成實(shí)例對象。利用這個(gè)方法和類的屬性的特點(diǎn)可以實(shí)現(xiàn)設(shè)計(jì)模式的單例模式馁筐。單例模式是指創(chuàng)建唯一對象涂召,單例模式設(shè)計(jì)的類只能實(shí)例使用__new__方法實(shí)現(xiàn) class Singleton(object): def __new__(cls, *args, **kw): if not hasattr(cls, '_instance'): orig = super(Singleton, cls) cls._instance = orig.__new__(cls, *args, **kw) return cls._instance class MyClass(Singleton): a = 1 import方法 作為python的模塊是天然的單例模式 # mysingleton.py class My_Singleton(object): def foo(self): pass my_singleton = My_Singleton() # to use from mysingleton import my_singleton my_singleton.foo() 裝飾器版本 def singleton(cls): instances = {} def getinstance(*args, **kw): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return getinstance @singleton class MyClass: ... 共享屬性實(shí)現(xiàn) 創(chuàng)建實(shí)例時(shí)把所有實(shí)例的__dict__指向同一個(gè)字典,這樣它們具有相同的屬性和方法. class Borg(object): _state = {} def __new__(cls, *args, **kw): ob = super(Borg, cls).__new__(cls, *args, **kw) ob.__dict__ = cls._state return ob class MyClass2(Borg): a = 1
字符串格式化方式有哪些?
%s(不推薦了),format敏沉,fstring(推薦)序列化(pickle和JSON)
通過dumps
和loads
進(jìn)行序列化和反序列化
json序列化保存中文`json.dumps({"name":"小明"},ensure)ascii=False)-
python字符串編碼芹扭?
"S".encode("gbk").decode("utf-8") 將編碼為GBK的字符“S”解碼成Unicode再編碼成utf-8
python常用模塊
常用內(nèi)建模塊
常用第三方模塊
操作系統(tǒng)
-
多進(jìn)程、多線程和協(xié)程的區(qū)別赦抖?
- 地址空間:線程是進(jìn)程內(nèi)的一個(gè)執(zhí)行單元舱卡,進(jìn)程內(nèi)至少有一個(gè)線程,它們共享進(jìn)程的地址空間队萤,
而進(jìn)程有自己獨(dú)立的地址空間 - 資源擁有:進(jìn)程是資源分配和擁有的單位,同一個(gè)進(jìn)程內(nèi)的線程共享進(jìn)程的資源
- 線程是處理器調(diào)度的基本單位,但進(jìn)程不是
- 二者均可并發(fā)執(zhí)行
- 每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口轮锥、順序執(zhí)行序列和程序的出口,
但是線程不能夠獨(dú)立執(zhí)行要尔,必須依存在應(yīng)用程序中舍杜,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制 - 一個(gè)線程可以多個(gè)協(xié)程,一個(gè)進(jìn)程也可以單獨(dú)擁有多個(gè)協(xié)程赵辕。
- 線程進(jìn)程都是同步機(jī)制既绩,而協(xié)程則是異步
- 協(xié)程能保留上一次調(diào)用時(shí)的狀態(tài),每次過程重入時(shí)还惠,就相當(dāng)于進(jìn)入上一次調(diào)用的狀態(tài)
- 地址空間:線程是進(jìn)程內(nèi)的一個(gè)執(zhí)行單元舱卡,進(jìn)程內(nèi)至少有一個(gè)線程,它們共享進(jìn)程的地址空間队萤,
-
線程同步方式饲握?
- 互斥鎖:通過互斥機(jī)制防止多個(gè)線程同時(shí)訪問公共資源
1.信號量:控制同一時(shí)刻多個(gè)線程訪問統(tǒng)一資源的線程數(shù) - 事件:通過通知的方式保持多個(gè)線程同步
- 互斥鎖:通過互斥機(jī)制防止多個(gè)線程同時(shí)訪問公共資源
-
進(jìn)程間通信的方式
- 管道:管道是通過調(diào)用 pipe 函數(shù)創(chuàng)建的,fd[0] 用于讀,fd[1] 用于寫救欧。
- 消息隊(duì)列: 間接(內(nèi)核)
相比于 FIFO衰粹,消息隊(duì)列具有以下優(yōu)點(diǎn):
消息隊(duì)列可以獨(dú)立于讀寫進(jìn)程存在,從而避免了 FIFO 中同步管道的打開和關(guān)閉時(shí)可能產(chǎn)生的困難笆怠;
避免了 FIFO 的同步阻塞問題铝耻,不需要進(jìn)程自己提供同步方法;
讀進(jìn)程可以根據(jù)消息類型有選擇地接收消息蹬刷,而不像 FIFO 那樣只能默認(rèn)地接收瓢捉。 - 信號量:它是一個(gè)計(jì)數(shù)器,用于為多個(gè)進(jìn)程提供對共享數(shù)據(jù)對象的訪問办成。
- 共享內(nèi)存:允許多個(gè)進(jìn)程共享一個(gè)給定的存儲(chǔ)區(qū)泡态。因?yàn)閿?shù)據(jù)不需要在進(jìn)程之間復(fù)制,所以這是最快的一種 IPC诈火。
需要使用信號量用來同步對共享存儲(chǔ)的訪問兽赁。
多個(gè)進(jìn)程可以將同一個(gè)文件映射到它們的地址空間從而實(shí)現(xiàn)共享內(nèi)存状答。另外 XSI 共享內(nèi)存不是使用文件冷守,而是使用使用內(nèi)存的匿名段。 - 套接字:與其它通信機(jī)制不同的是惊科,它可用于不同機(jī)器間的進(jìn)程通信拍摇。
python中如何使用多線程?
threading模塊
threading.Thread類用于創(chuàng)建線程
start()方法啟動(dòng)線程
可以用join()等待線程結(jié)束python中如何使用多進(jìn)程
multiprocessing模塊
Multiprocessing.Process類實(shí)現(xiàn)多進(jìn)程-
解釋什么是同步馆截、異步充活、阻塞、非阻塞蜡娶?
引用知乎回答
1.同步與異步
同步和異步關(guān)注的是消息通信機(jī)制 (synchronous communication/ asynchronous communication)
所謂同步混卵,就是在發(fā)出一個(gè)調(diào)用時(shí),在沒有得到結(jié)果之前窖张,該調(diào)用就不返回幕随。但是一旦調(diào)用返回,就得到返回值了宿接。
換句話說赘淮,就是由調(diào)用者主動(dòng)等待這個(gè)調(diào)用的結(jié)果。
而異步則是相反睦霎,調(diào)用在發(fā)出之后梢卸,這個(gè)調(diào)用就直接返回了,所以沒有返回結(jié)果副女。換句話說蛤高,當(dāng)一個(gè)異步過程調(diào)用發(fā)出后,調(diào)用者不會(huì)立刻得到結(jié)果。而是在調(diào)用發(fā)出后襟齿,被調(diào)用者通過狀態(tài)姻锁、通知來通知調(diào)用者,或通過回調(diào)函數(shù)處理這個(gè)調(diào)用猜欺。
阻塞和非阻塞關(guān)注的是程序在等待調(diào)用結(jié)果(消息位隶,返回值)時(shí)的狀態(tài).
阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起开皿。調(diào)用線程只有在得到結(jié)果之后才會(huì)返回涧黄。
非阻塞調(diào)用指在不能立刻得到結(jié)果之前,該調(diào)用不會(huì)阻塞當(dāng)前線程赋荆。 -
什么是死鎖笋妥?
原因:- 競爭資源
- 程序推進(jìn)順序不當(dāng)
必要條件:
- 互斥條件:每個(gè)資源要么已經(jīng)分配給了一個(gè)進(jìn)程,要么就是可用的窄潭。
- 請求和保持條件:已經(jīng)得到了某個(gè)資源的進(jìn)程可以再請求新的資源
- 不剝奪條件:已經(jīng)分配給一個(gè)進(jìn)程的資源不能強(qiáng)制性地被搶占春宣,它只能被占有它的進(jìn)程顯式地釋放。
- 環(huán)路等待條件:有兩個(gè)或者兩個(gè)以上的進(jìn)程組成一條環(huán)路嫉你,該環(huán)路中的每個(gè)進(jìn)程都在等待下一個(gè)進(jìn)程所占有的資源月帝。
處理死鎖基本方法:
- 預(yù)防死鎖(摒棄除1以外的條件)
- 避免死鎖(銀行家算法)
- 檢測死鎖(資源分配圖)
- 解除死鎖
- 剝奪資源
- 撤銷進(jìn)程
-
什么是分頁機(jī)制
邏輯地址和物理地址分離的內(nèi)存分配管理方案- 程序的邏輯地址劃分為固定大小的頁(page)
- 物理地址劃分同樣大小的幀
- 通過頁表對應(yīng)邏輯地址和物理地址
-
什么是分段機(jī)制
- 分段是為了滿足代碼的一些邏輯需求
- 數(shù)據(jù)共享,數(shù)據(jù)保護(hù)幽污,動(dòng)態(tài)鏈接等
- 通過段表實(shí)現(xiàn)邏輯地址和物理地址的映射關(guān)系
每個(gè)段內(nèi)部是連續(xù)內(nèi)存分配嚷辅,段和段之間是離散分配的
頁是出于內(nèi)存利用率的角度提出的離散分配機(jī)制
段是出于用戶角度,用戶數(shù)據(jù)保護(hù)距误,數(shù)據(jù)隔離等用途的管理機(jī)制
頁的大小是固定的簸搞,操作系統(tǒng)決定;段大小不確定准潭,用戶程序決定 -
什么是虛擬內(nèi)存
通過把一部分暫時(shí)不用的內(nèi)存信息放到硬盤上- 局部性原理(一塊內(nèi)存被訪問趁俊,時(shí)間上不遠(yuǎn)的將來還可能被訪問,空間上周圍的內(nèi)存也可能被訪問)刑然,程序運(yùn)行時(shí)候只有部分必要的信息裝入內(nèi)存
- 內(nèi)存中暫時(shí)不用的內(nèi)容放到硬盤上
- 系統(tǒng)似乎提供了比實(shí)際內(nèi)存大得多的容量寺擂,稱之為虛擬內(nèi)存
-
什么是內(nèi)存抖動(dòng)
本質(zhì)上是頻繁的頁調(diào)動(dòng)行為- 頻繁的頁調(diào)度,進(jìn)程不斷產(chǎn)生缺頁中斷
- 置換一個(gè)頁闰集,又不斷的再次需要這個(gè)頁
- 運(yùn)行程序太多沽讹,頁面替換策略不好。終止進(jìn)程,或增加物理內(nèi)存
-
python的垃圾回收機(jī)制
Python GC主要使用引用計(jì)數(shù)(reference counting)來跟蹤和回收垃圾。在引用計(jì)數(shù)的基礎(chǔ)上嗅回,通過“標(biāo)記-清除”(mark and sweep)解決容器對象可能產(chǎn)生的循環(huán)引用問題,通過“分代回收”(generation collection)以空間換時(shí)間的方法提高垃圾回收效率挚瘟。- 引用計(jì)數(shù)
PyObject是每個(gè)對象必有的內(nèi)容叹谁,其中ob_refcnt就是做為引用計(jì)數(shù)。當(dāng)一個(gè)對象有新的引用時(shí)乘盖,它的ob_refcnt就會(huì)增加焰檩,當(dāng)引用它的對象被刪除,它的ob_refcnt就會(huì)減少.引用計(jì)數(shù)為0時(shí)订框,該對象生命就結(jié)束了析苫。 - 標(biāo)記-清除機(jī)制
基本思路是先按需分配,等到?jīng)]有空閑內(nèi)存的時(shí)候從寄存器和程序棧上的引用出發(fā)穿扳,遍歷以對象為節(jié)點(diǎn)衩侥、以引用為邊構(gòu)成的圖,把所有可以訪問到的對象打上標(biāo)記矛物,然后清掃一遍內(nèi)存空間茫死,把所有沒標(biāo)記的對象釋放。 - 分代技術(shù)
分代回收的整體思想是:將系統(tǒng)中的所有內(nèi)存塊根據(jù)其存活時(shí)間劃分為不同的集合履羞,每個(gè)集合就成為一個(gè)“代”峦萎,垃圾收集頻率隨著“代”的存活時(shí)間的增大而減小,存活時(shí)間通常利用經(jīng)過幾次垃圾回收來度量忆首。
Python默認(rèn)定義了三代對象集合爱榔,索引數(shù)越大,對象存活時(shí)間越長雄卷。
舉例: 當(dāng)某些內(nèi)存塊M經(jīng)過了3次垃圾收集的清洗之后還存活時(shí)搓蚪,我們就將內(nèi)存塊M劃到一個(gè)集合A中去蛤售,而新分配的內(nèi)存都劃分到集合B中去丁鹉。當(dāng)垃圾收集開始工作時(shí),大多數(shù)情況都只對集合B進(jìn)行垃圾回收悴能,而對集合A進(jìn)行垃圾回收要隔相當(dāng)長一段時(shí)間后才進(jìn)行揣钦,這就使得垃圾收集機(jī)制需要處理的內(nèi)存少了,效率自然就提高了漠酿。在這個(gè)過程中冯凹,集合B中的某些內(nèi)存塊由于存活時(shí)間長而會(huì)被轉(zhuǎn)移到集合A中,當(dāng)然炒嘲,集合A中實(shí)際上也存在一些垃圾宇姚,這些垃圾的回收會(huì)因?yàn)檫@種分代的機(jī)制而被延遲。
- 引用計(jì)數(shù)
當(dāng)退出python時(shí)是否釋放所有內(nèi)存分配夫凸?
循環(huán)引用其他對象或引用自全局命名空間的對象的模塊浑劳,在 Python 退出時(shí)并非完全釋放。另外夭拌,也不會(huì)釋放 c 庫保留的內(nèi)存部分GIL全局解釋器鎖
每個(gè)線程在執(zhí)行的過程都需要先獲取 GIL魔熏,保證同一時(shí)刻只有一個(gè)線程可以執(zhí)行代碼衷咽。
線程釋放 GIL 鎖的情況:在 IO 操作等可能會(huì)引起阻塞的 systemcall 之前,可以暫時(shí)釋放 GIL,但在執(zhí)行完畢后, 必須重新獲取 GIL蒜绽,Python3.x 使用計(jì)時(shí)器(執(zhí)行時(shí)間達(dá)到閾值后镶骗,當(dāng)前線程釋放 GIL。
對于io密集型任務(wù)躲雅,python的多線程起到作用鼎姊,但對于cpu密集型任務(wù),python的多線程幾乎占不到任何優(yōu)勢相赁,還有可能因?yàn)闋帄Z資源而變慢此蜈。
計(jì)算機(jī)網(wǎng)絡(luò)
TCP和UDP?
TCP提供面向連接的噪生、可靠的數(shù)據(jù)流傳輸裆赵,而UDP提供的是非面向連接的、不可靠的數(shù)據(jù)流傳輸跺嗽。
TCP傳輸單位稱為TCP報(bào)文段战授,UDP傳輸單位稱為用戶數(shù)據(jù)報(bào)。
TCP注重?cái)?shù)據(jù)安全性桨嫁,UDP數(shù)據(jù)傳輸快植兰,因?yàn)椴恍枰B接等待,少了許多操作璃吧,但是其安全性卻一般楣导。
TCP對應(yīng)的協(xié)議和UDP對應(yīng)的協(xié)議
TCP對應(yīng)的協(xié)議:
(1) FTP:定義了文件傳輸協(xié)議,使用21端口畜挨。
(2) Telnet:一種用于遠(yuǎn)程登陸的端口筒繁,使用23端口,用戶可以以自己的身份遠(yuǎn)程連接到計(jì)算機(jī)上巴元,可提供基于DOS模式下的通信服務(wù)毡咏。
(3) SMTP:郵件傳送協(xié)議,用于發(fā)送郵件逮刨。服務(wù)器開放的是25號端口呕缭。
(4) POP3:它是和SMTP對應(yīng),POP3用于接收郵件修己。POP3協(xié)議所用的是110端口恢总。
(5)HTTP:是從Web服務(wù)器傳輸超文本到本地瀏覽器的傳送協(xié)議。
UDP對應(yīng)的協(xié)議:
(1) DNS:用于域名解析服務(wù)睬愤,將域名地址轉(zhuǎn)換為IP地址片仿。DNS用的是53號端口。
(2) SNMP:簡單網(wǎng)絡(luò)管理協(xié)議戴涝,使用161號端口滋戳,是用來管理網(wǎng)絡(luò)設(shè)備的钻蔑。由于網(wǎng)絡(luò)設(shè)備很多,無連接的服務(wù)就體現(xiàn)出其優(yōu)勢奸鸯。
(3) TFTP(Trival File Transfer Protocal)咪笑,簡單文件傳輸協(xié)議,該協(xié)議在熟知端口69上使用UDP服務(wù)娄涩。-
三次握手和四次揮手窗怒?
三次握手- 客戶端通過向服務(wù)器端發(fā)送一個(gè)SYN來創(chuàng)建一個(gè)主動(dòng)打開,作為三次握手的一部分蓄拣⊙镄椋客戶端把這段連接的序號設(shè)定為隨機(jī)數(shù) A。
- 服務(wù)器端應(yīng)當(dāng)為一個(gè)合法的SYN回送一個(gè)SYN/ACK球恤。ACK 的確認(rèn)碼應(yīng)為 A+1辜昵,SYN/ACK 包本身又有一個(gè)隨機(jī)序號 B。
- 最后咽斧,客戶端再發(fā)送一個(gè)ACK堪置。當(dāng)服務(wù)端受到這個(gè)ACK的時(shí)候,就完成了三路握手张惹,并進(jìn)入了連接創(chuàng)建狀態(tài)舀锨。此時(shí)包序號被設(shè)定為收到的確認(rèn)號 A+1,而響應(yīng)則為 B+1宛逗。
四次揮手
注意: 中斷連接端可以是客戶端坎匿,也可以是服務(wù)器端. 下面僅以客戶端斷開連接舉例, 反之亦然.- 客戶端發(fā)送一個(gè)數(shù)據(jù)分段, 其中的 FIN 標(biāo)記設(shè)置為1. 客戶端進(jìn)入 FIN-WAIT 狀態(tài). 該狀態(tài)下客戶端只接收數(shù)據(jù), 不再發(fā)送數(shù)據(jù).
- 服務(wù)器接收到帶有 FIN = 1 的數(shù)據(jù)分段, 發(fā)送帶有 ACK = 1 的剩余數(shù)據(jù)分段, 確認(rèn)收到客戶端發(fā)來的 FIN 信息.
- 服務(wù)器等到所有數(shù)據(jù)傳輸結(jié)束, 向客戶端發(fā)送一個(gè)帶有 FIN = 1 的數(shù)據(jù)分段, 并進(jìn)入 CLOSE-WAIT 狀態(tài), 等待客戶端發(fā)來帶有 ACK = 1 的確認(rèn)報(bào)文.
- 客戶端收到服務(wù)器發(fā)來帶有 FIN = 1 的報(bào)文, 返回 ACK = 1 的報(bào)文確認(rèn), 為了防止服務(wù)器端未收到需要重發(fā), 進(jìn)入 TIME-WAIT 狀態(tài). 服務(wù)器接收到報(bào)文后關(guān)閉連接. 客戶端等待 2MSL 后未收到回復(fù), 則認(rèn)為服務(wù)器成功關(guān)閉, 客戶端關(guān)閉連接.
TCP連接狀態(tài)?
CLOSED:初始狀態(tài)雷激。
LISTEN:服務(wù)器處于監(jiān)聽狀態(tài)替蔬。
SYN_SEND:客戶端socket執(zhí)行CONNECT連接,發(fā)送SYN包侥锦,進(jìn)入此狀態(tài)进栽。
SYN_RECV:服務(wù)端收到SYN包并發(fā)送服務(wù)端SYN包德挣,進(jìn)入此狀態(tài)恭垦。
ESTABLISH:表示連接建立「裥幔客戶端發(fā)送了最后一個(gè)ACK包后進(jìn)入此狀態(tài)番挺,服務(wù)端接收到ACK包后進(jìn)入此狀態(tài)。
FIN_WAIT_1:終止連接的一方(通常是客戶機(jī))發(fā)送了FIN報(bào)文后進(jìn)入屯掖。等待對方FIN玄柏。
CLOSE_WAIT:(假設(shè)服務(wù)器)接收到客戶機(jī)FIN包之后等待關(guān)閉的階段。在接收到對方的FIN包之后贴铜,自然是需要立即回復(fù)ACK包的粪摘,表示已經(jīng)知道斷開請求瀑晒。但是本方是否立即斷開連接(發(fā)送FIN包)取決于是否還有數(shù)據(jù)需要發(fā)送給客戶端,若有徘意,則在發(fā)送FIN包之前均為此狀態(tài)苔悦。
FIN_WAIT_2:此時(shí)是半連接狀態(tài),即有一方要求關(guān)閉連接椎咧,等待另一方關(guān)閉玖详。客戶端接收到服務(wù)器的ACK包勤讽,但并沒有立即接收到服務(wù)端的FIN包蟋座,進(jìn)入FIN_WAIT_2狀態(tài)。
LAST_ACK:服務(wù)端發(fā)動(dòng)最后的FIN包脚牍,等待最后的客戶端ACK響應(yīng)向臀,進(jìn)入此狀態(tài)。
TIME_WAIT:客戶端收到服務(wù)端的FIN包诸狭,并立即發(fā)出ACK包做最后的確認(rèn)飒硅,在此之后的2MSL時(shí)間稱為TIME_WAIT狀態(tài)。在瀏覽器中輸入網(wǎng)址后執(zhí)行的全部過程
1.查詢DNS獲取域名對應(yīng)IP 2.瀏覽器與對應(yīng)IP發(fā)起HTTP三次握手 3.TCP/IP連接建立起來之后瀏覽器就可以向服務(wù)器發(fā)送HTTP請求了 4. TLS握手 5. HTTP服務(wù)器請求處理并根據(jù)請求參數(shù)返回一些經(jīng)過后端處理生成的HTML頁面代碼 6.瀏覽器拿到代碼開始解析和渲染作谚,最終把完整的頁面呈現(xiàn)給用戶-
HTTP是無狀態(tài)的如何實(shí)現(xiàn)識(shí)別用戶呢三娩?(Cookie和Session)
- session一般是服務(wù)器生成之后給客戶端(通過url參數(shù)或cookie)
- cookie是實(shí)現(xiàn)session的一種機(jī)制,通過HTTPcookie字段實(shí)現(xiàn)
- session通過在服務(wù)器保存sessionid識(shí)別用戶客戶端
-
HTTP和HTTPS的區(qū)別
- http是HTTP協(xié)議運(yùn)行在TCP之上妹懒。所有傳輸?shù)膬?nèi)容都是明文雀监,客戶端和服務(wù)器端都無法驗(yàn)證對方的身份。
- https是HTTP運(yùn)行在SSL/TLS之上眨唬,SSL/TLS運(yùn)行在TCP之上会前。所有傳輸?shù)膬?nèi)容都經(jīng)過加密,加密采用對稱加密匾竿,但對稱加密的密鑰用服務(wù)器方的證書進(jìn)行了非對稱加密瓦宜。此外客戶端可以驗(yàn)證服務(wù)器端的身份,如果配置了客戶端驗(yàn)證岭妖,服務(wù)器方也可以驗(yàn)證客戶端的身份临庇。
- https協(xié)議需要到ca申請證書,一般免費(fèi)證書很少昵慌,需要交費(fèi)假夺。
- http是超文本傳輸協(xié)議,信息是明文傳輸斋攀,https 則是具有安全性的ssl加密傳輸協(xié)議
- http和https使用的是完全不同的連接方式用的端口也不一樣,前者是80,后者是443已卷。
- http的連接很簡單,是無狀態(tài)的
- HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議 要比http協(xié)議安全
請求和響應(yīng)的組成淳蔼?
請求:狀態(tài)行 (POST / HTTP/1.1)請求頭(常用HTTP請求頭)消息主體(GET為空)
響應(yīng):狀態(tài)行(HTTP/1.1 200 OK)響應(yīng)頭(常見HTTP響應(yīng)頭)響應(yīng)正文-
常見響應(yīng)狀態(tài)碼侧蘸?
狀態(tài)碼 類別 原因短語 1XX Informational(信息性狀態(tài)碼) 接收的請求正在處理 2XX Success(成功狀態(tài)碼) 請求正常處理完畢 3XX Redirection(重定向狀態(tài)碼) 需要進(jìn)行附加操作以完成請求 4XX Client Error(客戶端錯(cuò)誤狀態(tài)碼) 服務(wù)器無法處理請求 5XX Server Error(服務(wù)器錯(cuò)誤狀態(tài)碼) 服務(wù)器處理請求出錯(cuò) 100 Continue :表明到目前為止都很正常裁眯,客戶端可以繼續(xù)發(fā)送請求或者忽略這個(gè)響應(yīng)。
200 OK
301 Moved Permanently :永久性重定向
302 Found :臨時(shí)性重定向
400 Bad Request :請求報(bào)文中存在語法錯(cuò)誤讳癌。
401 Unauthorized :該狀態(tài)碼表示發(fā)送的請求需要有認(rèn)證信息(BASIC 認(rèn)證未状、DIGEST 認(rèn)證)。如果之前已進(jìn)行過一次請求析桥,則表示用戶認(rèn)證失敗司草。
403 Forbidden :請求被拒絕,服務(wù)器端沒有必要給出拒絕的詳細(xì)理由泡仗。
404 Not Found
500 Internal Server Error :服務(wù)器正在執(zhí)行請求時(shí)發(fā)生錯(cuò)誤埋虹。
503 Service Unavailable :服務(wù)器暫時(shí)處于超負(fù)載或正在進(jìn)行停機(jī)維護(hù),現(xiàn)在無法處理請求娩怎。 GET和POST的區(qū)別
GET 被強(qiáng)制服務(wù)器支持
瀏覽器對URL的長度有限制搔课,所以GET請求不能代替POST請求發(fā)送大量數(shù)據(jù)
GET請求發(fā)送數(shù)據(jù)更小
GET請求是不安全的
GET請求是冪等的
冪等的意味著對同一URL的多個(gè)請求應(yīng)該返回同樣的結(jié)果
POST請求不能被緩存
POST請求相對GET請求是「安全」的
這里安全的含義僅僅是指是非修改信息
GET用于信息獲取,而且是安全的和冪等的
所謂安全的意味著該操作用于獲取信息而非修改信息截亦。換句話說爬泥,GET 請求一般不應(yīng)產(chǎn)生副作用。就是說崩瓤,它僅僅是獲取資源信息袍啡,就像數(shù)據(jù)庫查詢一樣,不會(huì)修改却桶,增加數(shù)據(jù)境输,不會(huì)影響資源的狀態(tài)。
POST是用于修改服務(wù)器上的資源的請求
發(fā)送包含未知字符的用戶輸入時(shí)颖系,POST 比 GET 更穩(wěn)定也更可靠
引申:說完原理性的問題嗅剖,我們從表面上來看看GET和POST的區(qū)別:
GET是從服務(wù)器上獲取數(shù)據(jù),POST是向服務(wù)器傳送數(shù)據(jù)嘁扼。 GET和 POST只是一種傳遞數(shù)據(jù)的方式信粮,GET也可以把數(shù)據(jù)傳到服務(wù)器,他們的本質(zhì)都是發(fā)送請求和接收結(jié)果趁啸。只是組織格式和數(shù)據(jù)量上面有差別强缘,http協(xié)議里面有介紹
GET是把參數(shù)數(shù)據(jù)隊(duì)列加到提交表單的ACTION屬性所指的URL中,值和表單內(nèi)各個(gè)字段一一對應(yīng)莲绰,在URL中可以看到欺旧。POST是通過HTTP POST機(jī)制,將表單內(nèi)各個(gè)字段與其內(nèi)容放置在HTML HEADER內(nèi)一起傳送到ACTION屬性所指的URL地址蛤签。用戶看不到這個(gè)過程。 因?yàn)镚ET設(shè)計(jì)成傳輸小數(shù)據(jù)栅哀,而且最好是不修改服務(wù)器的數(shù)據(jù)震肮,所以瀏覽器一般都在地址欄里面可以看到称龙,但POST一般都用來傳遞大數(shù)據(jù),或比較隱私的數(shù)據(jù)戳晌,所以在地址欄看不到鲫尊,能不能看到不是協(xié)議規(guī)定,是瀏覽器規(guī)定的沦偎。
對于GET方式疫向,服務(wù)器端用Request.QueryString獲取變量的值,對于POST方式豪嚎,服務(wù)器端用Request.Form獲取提交的數(shù)據(jù)搔驼。 沒明白,怎么獲得變量和你的服務(wù)器有關(guān)侈询,和GET或POST無關(guān)舌涨,服務(wù)器都對這些請求做了封裝
GET傳送的數(shù)據(jù)量較小,不能大于2KB扔字。POST傳送的數(shù)據(jù)量較大囊嘉,一般被默認(rèn)為不受限制。但理論上革为,IIS4中最大量為80KB扭粱,IIS5中為100KB。 POST基本沒有限制震檩,我想大家都上傳過文件焊刹,都是用POST方式的。只不過要修改form里面的那個(gè)type參數(shù)
GET安全性非常低恳蹲,POST安全性較高虐块。 如果沒有加密,他們安全級別都是一樣的嘉蕾,隨便一個(gè)監(jiān)聽器都可以把所有的數(shù)據(jù)監(jiān)聽到贺奠。長/短連接的優(yōu)缺點(diǎn)?
長連接可以省去較多的TCP建立和關(guān)閉的操作错忱,減少浪費(fèi)儡率,節(jié)約時(shí)間。
對于頻繁請求資源的客戶來說以清,較適用長連接儿普。
client與server之間的連接如果一直不關(guān)閉的話,會(huì)存在一個(gè)問題掷倔,
隨著客戶端連接越來越多眉孩,server早晚有扛不住的時(shí)候,這時(shí)候server端需要采取一些策略,
如關(guān)閉一些長時(shí)間沒有讀寫事件發(fā)生的連接浪汪,這樣可以避免一些惡意連接導(dǎo)致server端服務(wù)受損巴柿;
如果條件再允許就可以以客戶端機(jī)器為顆粒度,限制每個(gè)客戶端的最大長連接數(shù)死遭,
這樣可以完全避免某個(gè)蛋疼的客戶端連累后端服務(wù)广恢。
短連接對于服務(wù)器來說管理較為簡單,存在的連接都是有用的連接呀潭,不需要額外的控制手段钉迷。
但如果客戶請求頻繁,將在TCP的建立和關(guān)閉操作上浪費(fèi)時(shí)間和帶寬钠署。TCP長/短連接的應(yīng)用場景糠聪?
長連接多用于操作頻繁,點(diǎn)對點(diǎn)的通訊踏幻,而且連接數(shù)不能太多情況枷颊。
每個(gè)TCP連接都需要三次握手,這需要時(shí)間该面,如果每個(gè)操作都是先連接夭苗,
再操作的話那么處理速度會(huì)降低很多,所以每個(gè)操作完后都不斷開隔缀,
再次處理時(shí)直接發(fā)送數(shù)據(jù)包就OK了题造,不用建立TCP連接。
例如:數(shù)據(jù)庫的連接用長連接猾瘸,如果用短連接頻繁的通信會(huì)造成socket錯(cuò)誤界赔,
而且頻繁的socket 創(chuàng)建也是對資源的浪費(fèi)。
而像WEB網(wǎng)站的http服務(wù)一般都用短鏈接牵触,因?yàn)殚L連接對于服務(wù)端來說會(huì)耗費(fèi)一定的資源淮悼,
而像WEB網(wǎng)站這么頻繁的成千上萬甚至上億客戶端的連接用短連接會(huì)更省一些資源,
如果用長連接揽思,而且同時(shí)有成千上萬的用戶袜腥,如果每個(gè)用戶都占用一個(gè)連接的話,
那可想而知吧钉汗。所以并發(fā)量大羹令,但每個(gè)用戶無需頻繁操作情況下需用短連好。什么是IO多路復(fù)用损痰?
操作系統(tǒng)提供的同事監(jiān)聽多個(gè)socket的機(jī)制福侈,一般阻塞 I/O 只能阻塞一個(gè) I/O 操作,而 I/O 復(fù)用模型能夠阻塞多個(gè) I/O 操作卢未,所以才叫做多路復(fù)用肪凛。
I/O 多路復(fù)用是用于提升效率堰汉,單個(gè)進(jìn)程可以同時(shí)監(jiān)聽多個(gè)網(wǎng)絡(luò)連接 IO。 在 IO 密集型的系統(tǒng)中显拜, 相對于線程切換的開銷問題衡奥,IO 多路復(fù)用可以極大的提升系統(tǒng)效率爹袁。select远荠、poll、epoll 模型的區(qū)別失息?
select譬淳,poll,epoll 都是 IO 多路復(fù)用的機(jī)制盹兢。I/O 多路復(fù)用就通過一種機(jī)制邻梆,可以監(jiān)視多個(gè)描述符,一旦某個(gè)描述符就緒(一般是讀就緒或者寫就緒)绎秒,能夠通知程序進(jìn)行相應(yīng)的讀寫操作浦妄。
select 模型: select 目前幾乎在所有的平臺(tái)上支持,其良好跨平臺(tái)支持也是它的一個(gè)優(yōu)點(diǎn)见芹。select 的一 個(gè)缺點(diǎn)在于單個(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制剂娄,在 Linux 上一般為 1024,可以通過修改宏定義甚至重新編譯內(nèi)核的方式提升這一限制玄呛,但 是這樣也會(huì)造成效率的降低阅懦。
poll 模型: poll 和 select 的實(shí)現(xiàn)非常類似,本質(zhì)上的區(qū)別就是存放 fd 集合的數(shù)據(jù)結(jié)構(gòu)不一樣徘铝。select 在一個(gè)進(jìn)程內(nèi)可以維持最多 1024 個(gè)連接耳胎,poll 在此基礎(chǔ)上做了加強(qiáng),可以維持任意數(shù)量的連接惕它。
但 select 和 poll 方式有一個(gè)很大的問題就是怕午,我們不難看出來 select 是通過輪訓(xùn)的方式來查找是否可讀或者可寫,打個(gè)比方淹魄,如果同時(shí)有 100 萬個(gè)連接都沒有斷開郁惜,而只有一個(gè)客戶端發(fā)送了數(shù)據(jù),所以這里它還是需要循環(huán)這么多次揭北,造成資源浪費(fèi)扳炬。所以后來出現(xiàn)了 epoll 系統(tǒng)調(diào)用。
epoll 模型: epoll 是 select 和 poll 的增強(qiáng)版搔体,epoll 同 poll 一樣恨樟,文件描述符數(shù)量無限制。但是也并不是所有情況下 epoll 都比 select/poll 好疚俱,比如在如下場景:在大多數(shù)客戶端都很活躍的情況下劝术,系統(tǒng)會(huì)把所有的回調(diào)函數(shù)都喚醒,所以會(huì)導(dǎo)致負(fù)載較高。既然要處理這么多的連接养晋,那倒不如 select 遍歷簡單有效衬吆。
數(shù)據(jù)庫
什么是事務(wù)?
數(shù)據(jù)庫事務(wù)(Database Transaction) 绳泉,是指作為單個(gè)邏輯工作單元執(zhí)行的一系列操作逊抡,要么完全地執(zhí)行,要么完全地不執(zhí)行零酪。
AUTOCOMMIT
MySQL 默認(rèn) 自動(dòng)提交模式冒嫡。也就是說,如果不顯式使用 START TRANSACTION 語句來開始一個(gè)事務(wù)四苇,那么每個(gè)查詢都會(huì)被當(dāng)做一個(gè)事務(wù)自動(dòng)提交-
數(shù)據(jù)庫ACID孝凌?
原子性:一個(gè)事務(wù)中所有操作全部成功或失敗
一致性:事務(wù)開始和結(jié)束之后數(shù)據(jù)完整性沒有被破壞
隔離性:允許多個(gè)事務(wù)同時(shí)對數(shù)據(jù)庫修改和讀取
持久性:事務(wù)結(jié)束后,修改是用久不會(huì)丟失的
三范式月腋?
1NF:屬性不可分
2NF:屬性完全依賴于主鍵 [消除部分子函數(shù)依賴]
3NF:屬性不依賴于其它非主屬性 [消除傳遞依賴]并發(fā)一致性問題蟀架?
丟失修改:并發(fā)的寫入造成其中一些修改丟失
臟讀:一個(gè)事務(wù)讀取到另一個(gè)事務(wù)沒有提交的修改
幻讀:在一個(gè)事務(wù)第二次查出現(xiàn)第一次沒有的結(jié)構(gòu)
非重復(fù)讀:一個(gè)事務(wù)重復(fù)讀兩次得到的結(jié)果不一樣事務(wù)隔離級別(為解決并發(fā)異常)
每種隔離級別解決一個(gè)問題
讀未提交:的的事務(wù)可以讀取到未提交的改變
讀已提交:只能讀取已經(jīng)提交的數(shù)據(jù)
可重復(fù)讀:同一事務(wù)先后查詢結(jié)果一樣(mysql innoDB默認(rèn)實(shí)現(xiàn)可重復(fù)讀級別)
串行化:事務(wù)玩去串行化的執(zhí)行,隔離級別最高榆骚,執(zhí)行效率最低-
你所知道的鎖片拍?
樂觀鎖(先修改,更新時(shí)發(fā)現(xiàn)數(shù)據(jù)已經(jīng)變了就回滾)
用數(shù)據(jù)版本(Version)記錄機(jī)制實(shí)現(xiàn)寨躁,這是樂觀鎖最常用的一種實(shí)現(xiàn)方式穆碎。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識(shí)职恳,一般是通過為數(shù)據(jù)庫表增加一個(gè)數(shù)字類型的 “version” 字段來實(shí)現(xiàn)所禀。當(dāng)讀取數(shù)據(jù)時(shí),將version字段的值一同讀出放钦,數(shù)據(jù)每更新一次色徘,對此version值加1。當(dāng)我們提交更新的時(shí)候操禀,判斷數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息與第一次取出來的version值進(jìn)行比對褂策,如果數(shù)據(jù)庫表當(dāng)前版本號與第一次取出來的version值相等,則予以更新颓屑,否則認(rèn)為是過期數(shù)據(jù)斤寂。
悲觀鎖(一鎖二查三更新)
與樂觀鎖相對應(yīng)的就是悲觀鎖了。悲觀鎖就是在操作數(shù)據(jù)時(shí)揪惦,認(rèn)為此操作會(huì)出現(xiàn)數(shù)據(jù)沖突遍搞,所以在進(jìn)行每次操作時(shí)都要通過獲取鎖才能進(jìn)行對相同數(shù)據(jù)的操作,所以悲觀鎖需要耗費(fèi)較多的時(shí)間器腋。另外與樂觀鎖相對應(yīng)的溪猿,悲觀鎖是由數(shù)據(jù)庫自己實(shí)現(xiàn)了的钩杰,要用的時(shí)候,我們直接調(diào)用數(shù)據(jù)庫的相關(guān)語句就可以了诊县。-
排它鎖
使用方式:在需要執(zhí)行的語句后面加上 for update 就可以了
排它鎖exclusive lock(也叫 writer lock)又稱寫鎖讲弄。排它鎖是悲觀鎖的一種實(shí)現(xiàn)。
若事務(wù) 1 對數(shù)據(jù)對象 A 加上 X 鎖依痊,事務(wù) 1 可以讀 A 也可以修改 A避除,其他事務(wù)不能再對 A 加任何鎖,直到事物 1 釋放 A 上的鎖抗悍。這保證了其他事務(wù)在事物 1 釋放 A 上的鎖之前不能再讀取和修改 A驹饺。排它鎖會(huì)阻塞所有的排它鎖和共享鎖
讀取為什么要加讀鎖呢:防止數(shù)據(jù)在被讀取的時(shí)候被別的線程加上寫鎖
-
共享鎖
共享鎖又稱讀鎖(read lock)钳枕,是讀取操作創(chuàng)建的鎖缴渊。其他用戶可以并發(fā)讀取數(shù)據(jù),但任何事務(wù)都不能對數(shù)據(jù)進(jìn)行修改(獲取數(shù)據(jù)上的排他鎖)鱼炒,直到已釋放所有共享鎖衔沼。
如果事務(wù) T 對數(shù)據(jù) A 加上共享鎖后,則其他事務(wù)只能對 A 再加共享鎖昔瞧,不能加排他鎖指蚁。獲得共享鎖的事務(wù)只能讀數(shù)據(jù),不能修改數(shù)據(jù)
在查詢語句后面增加 lock in share mode自晰,MySQL 會(huì)對查詢結(jié)果中的每行都加共享鎖凝化,當(dāng)沒有其他線程對查詢結(jié)果集中的任何一行使用排他鎖時(shí),可以成功申請共享鎖酬荞,否則會(huì)被阻塞搓劫。其他線程也可以讀取使用了共享鎖的表,而且這些線程讀取的是同一個(gè)版本的數(shù)據(jù)混巧。
加上共享鎖后枪向,對于 update,insert,delete 語句會(huì)自動(dòng)加排它鎖。
-
什么是索引咧党?
索引是數(shù)據(jù)表中一個(gè)或多個(gè)列進(jìn)行排序的數(shù)據(jù)結(jié)構(gòu)
索引能大幅度提升檢索速度
創(chuàng)建秘蛔、更新索引本身也會(huì)消耗時(shí)間和空間什么是B-Tree?
多路平衡查找樹(每個(gè)節(jié)點(diǎn)最多m(m>=2)個(gè)孩子傍衡,稱為m階或者度)
葉節(jié)點(diǎn)具有相同的深度
節(jié)點(diǎn)中的數(shù)據(jù)key從左到右是遞增的什么是B+Tree深员?
mysql實(shí)際使用B+Tree作為輸贏的數(shù)據(jù)結(jié)構(gòu)
只在葉子節(jié)點(diǎn)帶有指向記錄的指針(可以增加樹的度)
葉子節(jié)點(diǎn)通過指針相連(實(shí)現(xiàn)范圍查找)mysql索引類型
普通索引CREATE INDEX
唯一索引,索引列的值必須唯一CREATE UNIQUE INDEX
主鍵索引PRIMARY KEY
一個(gè)表只能有一個(gè)
全文索引FULLTEXT INDEX
蛙埂,InnoDB不支持什么時(shí)候創(chuàng)建索引倦畅?
經(jīng)常用到查詢條件的字段WHERE條件
經(jīng)常用作表連接的字段
經(jīng)常出現(xiàn)在ORDER BY, GROUP BY
之后的字段知道Redis嗎?
是一個(gè)完全開源免費(fèi)的key-value內(nèi)存數(shù)據(jù)庫
通常被認(rèn)為是一個(gè)數(shù)據(jù)結(jié)構(gòu)服務(wù)器箱残,主要是因?yàn)槠溆兄S富的數(shù)據(jù)結(jié)構(gòu)
string:可以是字符串滔迈、整數(shù)或浮點(diǎn)數(shù)
list:一個(gè)鏈表止吁,鏈表上的每個(gè)節(jié)點(diǎn)都包含了一個(gè)字符串
set:包含字符串的無序收集器,并且被包含的每個(gè)字符串都是獨(dú)一無二的燎悍、各不相同
zset:字符串成員與浮點(diǎn)數(shù)分值之間的有序映射敬惦,元素的排列順序由分值的大小決定
hash:包含鍵值對的無序散列表-
了解Redis的事務(wù)嗎?
簡單理解谈山,可以認(rèn)為 redis 事務(wù)是一些列 redis 命令的集合俄删,并且有如下兩個(gè)特點(diǎn): 1.事務(wù)是一個(gè)單獨(dú)的隔離操作:事務(wù)中的所有命令都會(huì)序列化、按順序地執(zhí)行奏路。事務(wù)在執(zhí)行的過程中畴椰,不會(huì)被其他客戶端發(fā)送來的命令請求所打斷。 2.事務(wù)是一個(gè)原子操作:事務(wù)中的命令要么全部被執(zhí)行鸽粉,要么全部都不執(zhí)行斜脂。 一般來說,事務(wù)有四個(gè)性質(zhì)稱為ACID触机,分別是原子性帚戳,一致性,隔離性和持久性儡首。 一個(gè)事務(wù)從開始到執(zhí)行會(huì)經(jīng)歷以下三個(gè)階段:開始事務(wù)片任、命令入隊(duì)、執(zhí)行事務(wù)
代碼示例:import redis import sys def run(): try: conn=redis.StrictRedis('192.168.80.41') # Python中redis事務(wù)是通過pipeline的封裝實(shí)現(xiàn)的 pipe=conn.pipeline() pipe.sadd('s001','a') sys.exit() #在事務(wù)還沒有提交前退出蔬胯,所以事務(wù)不會(huì)被執(zhí)行对供。 pipe.sadd('s001','b') pipe.execute() pass except Exception as err: print(err) pass if __name__=="__main__": run()