Python面試題

1.列出5個常用python標準庫

(1)os:提供與操作系統相關聯的函數

(2)re:正則匹配

(3)sys:通常用於命令行參數

(4)math:數學運算

(5)datatime:處理日期時間

2.簡述with方法打開文件幫我們做了什麼?

with語句適用於對資源進行訪問的場合,確保不管使用過程中是否發生異常都會執行必要的‘清理’操作,釋放資源,比如文件使用後自動關閉、線程中鎖的自動獲取和釋放等

with語句即’上下文管理器‘,在程序中用來表示代碼執行過程中所處的前後環境,含有__enter__和__exit__方法的對象就是上下文管理器

__enter__():在執行語句之前,首先執行該方法,通常返回一個實例對象,如果with語句有as目標,則將對象賦值給as目標

__exit__():執行語句結束後,自動調用該方法,用戶釋放資源,若此方法返回布爾值True,程序會忽略異常

使用環境:文件讀寫、線程鎖的自動釋放等

3.列出python中可變數據類型和不可變數據類型,爲什麼?

不可變數據類型:數值型、字符串型和元組

不允許變量的值發生改變,如果改變了變量的值,相當於新建了一個對象,而對於相同的值的對象,在內存中則只有一個對象(一個地址),用id()方法可以打印對象的id(id方法的返回值就是對象的內存地址)

可變數據類型:列表和字典、集合

允許變量的值發生變化,即如果對變量進行append、+=等操作後,只是改變了變量的值,而不會新建一個對象,變量引用的對象的地址不會變化,不過對於相同的值的不同對象,在內存中則會存在不同的對象。即每個對象都有自己的地址,相當於內存中對於同值的對象保存了多份,這裏不存在引用計數,是實實在在的對象

4.Python 和其他語言的區別

Python是一門語言簡潔優美,功能強大,應用領域廣泛,具有強大完備的第三方庫的一門弱類型的可移植、可擴展、可嵌入的解釋型編程語言

與java相比:python比java要簡單。python是函數爲一等公民的語言,而java是類爲一等公民的語言。python是弱類型語言,而java是強類型語言

與c相比:

對於使用:python的類庫齊全並且使用簡潔,很少代碼實現的功能用c可能要很複雜

對於速度:python的運行速度相較於c絕對是很慢了。python和CPython解釋器都是c語言編寫的

5.Python 的解釋器種類以及相關特點?

CPython:c語言開發的,使用最廣的解釋器

IPython:基於cpython之上的一個交互式計時器,交互方式增強,功能和cpython一樣

PyPy:目標是執行效率,採用JIT技術,對python代碼進行動態編譯,提高執行效率

JPython:運行在java上的解釋器,直接把python代碼編譯成java字節碼執行

IronPython:運行在微軟.NET平臺上的解釋器,把python編譯成.NET的字節碼

6.Python3 和 Python2 之間的區別?

(1)python3 使用 print 必須要以小括號包裹打印內容,比如 print('hi')
         python2 既可以使用帶小括號的方式,也可以使用一個空格來分隔打印內容,如 print 'hi'
(2)python2 range(1,10)返回列表,python3中返回迭代器,節約內存
(3)python2中使用ascii編碼,python3中使用utf-8編碼
(4)python2中unicode表示字符串序列,str表示字節序列
         python3中str表示字符串序列,byte表示字節序列
(5)python2中爲正常顯示中文,引入coding聲明,python3中不需要
(6)python2中是raw_input()函數,python3中是input()函數

7.給定兩個list,A和B,找出相同元素和不同元素

A、B中相同元素:print(set(A)&set(B))

A、B中不同元素:print(set(A)^set(B))

8.合併列表[1,5,7,9]和[2,2,6,8]

(1)a=[1,5,7,9]     b=[2,2,6,8]       a+b

(2)a.extend(b)       print(a)

9.如何打亂一個列表的元素?

random.shuffle(a)

10.字典操作中del和pop有什麼區別?

del可以刪除指定key的鍵值對,沒有返回值。pop是從字典中取走指定key的鍵值對,並且返回鍵值

11.合併下面兩個字典a={“A”:1,”B”:2},b={“C”:3,”D”:4}

方法(1)a.update(b)  print(a)

       (2)字典的dict(d1, **d2)方法和(**d1,**d2)方法  eg:print({**a,**b})

12.在讀文件操作的時候會使用read、readline或者readlines,簡述它們各自的作用

read()每次讀取整個文件,它通常用於將文件內容放到一個字符串變量中

readline()一行一行的輸出,該方法會把文件的內容加載到內存,所以對於大文件的讀取操作來說非常的消耗內存資源,此時就可以通過readlines方法,將文件的句柄生成一個生產器,然後去讀就可以了

13.說一說 Redis 的基本類型。

Redis支持五種數據類型:string(字符串)、hash、list、set、zset(有序集合)

14.請寫一段 Python連接 Redis 數據庫的代碼。

import redis #創建連接池

pool = redis.ConnectionPool(host=’localhost’, port=6379, password=’a’,db=0)

r = redis.Redis(connection_pool = pool) #獲取連接對象

r.flushdb() #清空數據庫

r.set(‘name’,’value’) #設置一個鍵值

r.get(‘name’)

15.請寫一段 Python 連接 MySQL 數據庫的代碼。

import pymysql

db = pymysql.connect(host=‘localhost’,port=3306,user=’root’,passwd=

’1234’,db=’user’,charset=’utf8’) #打開數據庫連接

cursor = db.cursor() #獲取操作遊標

cursor.execute(‘sql語句’) #使用execute方法執行sql語句

data = cursor.fetchone() #獲取一條數據

db.close()

16.瞭解 Redis 的事務麼?

事務提供了一種‘將多個命令打包,一次性提交併按順序執行’的機制,提交後在事務執行中不會中斷。只有在執行完所有命令後纔會繼續執行來自其他客戶的消息

Redis通過multi,exec,discard,watch實現事務功能

Multi:開始事務

Exec:提交事務並執行

Discard:取消事務

Watch:事務開始之前監視任意數量的鍵

Unwatch:取消watch命令對所有key的監控,所有監控鎖將會被取消

關於事務管理:

(1)單獨的隔離操作:事務中的所有命令會被序列化、按順序執行,在執行的過程中不會被其他客戶端發送來的命令打斷

(2)沒有隔離級別的概念:隊列中的命令在事務沒有被提交之前不會被實際執行

(3)不保證原子性:redis中的一個事務中如果存在命令執行失敗,那麼其他命令依然會被執行,沒有回滾機制

17.瞭解分佈式鎖麼?

分佈式鎖是控制分佈式系統之間的同步訪問共享資源的一種方式。對於分佈式鎖的目標,我們必須首先明確三點:(1)任何一個時間點必須只能有一個客戶端擁有鎖(2)不能有死鎖,也就是最終客戶端都能夠獲得鎖,儘管可能會經歷失敗(3)錯誤容忍性要好,只要有大部分的redis實例存活,客戶端就應該能夠獲得鎖

分佈式鎖的條件:(1)互斥性:分佈式鎖需要保證在不同節點的不同線程的互斥(2)可重入性:同一個節點上的同一個線程如果獲取了鎖之後,能夠再次獲取這個鎖(3)鎖超時:支持超時釋放鎖,防止死鎖(4)高效、高可用:加鎖和解鎖需要高效,同時也需要保證高可用防止分佈式鎖失效,可以增加降級(5)支持阻塞和非阻塞:可以實現超時獲取失敗,tryLock支持公平鎖和非公平鎖

分佈式鎖實現方案(1)數據庫實現(樂觀鎖)(2)基於zookeeper的實現(3)基於redis的實現

18.函數裝飾器有什麼作用?請列舉說明?

Python裝飾器本質上就是一個函數,它可以讓其他函數在不需要做任何代碼變動的前提下增加額外的功能,裝飾器返回值也是一個函數對象(函數的指針)

應用場景:(1)引入日誌(2)函數執行時間統計(3)執行函數前預備處理(4)執行函數後清理功能(5)權限校驗等場景(6)緩存(7)事務處理

19.@classmethod 和@staticmethod 用法和區別

@classmathod:是類方法,訪問和修改類屬性,進行類相關的操作,通過類或實例對象調用,需要傳遞cls類對象爲參數

@staticmethod:靜態方法,不訪問類屬性和實例屬性,通過類或實例調用,相當於一個普通函數

20.Python 中的反射了解麼?

計算機中的反射是在運行的時候來自我檢查,並對內部成員進行操作。就是說這個變量的類型可以動態的改變,在運行的時候確定它的作用

在python中能夠通過一個對象,找出其type、class、attribute或method的能力,稱爲反射或自省。具有反射能力的函數有type(),isinstance(),callable().dir().getattr()等

21.hasattr() getattr() setattr()的用法

這三種方法用於爲對象屬性的存在判斷、獲取和添加修改,簡言之就是對象屬性的‘增改查’

hasattr(object,name):判斷對象是否存在name屬性

getattr(object,name[,default]):獲取object對象name屬性的值,若沒有name屬性,則返回default值

setattr(object,name,value):給object對象的name屬性賦值value,如果對象原本存在給定的屬性name,則setattr會更改屬性的值爲給定的value,如果不存在屬性name,會在對象中創建屬性並賦值value

22.請列舉你知道的 Python 的魔法方法及用途。

__new__用來創建類並返回這個類的實例

__init__將傳入的參數來初始化該實例,以及初始化實例屬性,與__new__共同構成了‘構造函數’

__del__將實例化後的對象銷燬,即爲析構函數

類調用:__call__允許一個類像函數一樣被調用

屬性訪問:__getattr__訪問對象不存在的屬性時,調用該方法,用於定義訪問行爲

                  __setattr__設置對象屬性時調用

                  __delattr__刪除對象屬性時調用

上下文管理器:__enter__():在執行語句之前,首先執行該方法,通常返回一個實例對象,如果with語句有as目標,則將對象賦值給as目標

                         __exit__():執行語句結束後,自動調用該方法,用戶釋放資源,若此方法返回布爾值True,程序會忽略異常

迭代器方法:__iter__:返回一個容器迭代器,很多情況下會返回迭代器,尤其是當內置的iter()方法被調用時,以及當使用for x in container:方法循環的時候。迭代器是它們本身的對象,它們必須定義返回self的__iter__方法

                      __next__:返回迭代器的下一個元素

23.Python 的傳參是傳值還是傳址?

Python對可變對象(字典或列表)傳址,對不可變對象(數字、字符或元組)傳值

24.在 Python 中是如何管理內存的?

Python內存池:內存池的概念就是預先在內存中申請一定數量的,大小相等的內存塊留作備用,當有新的內存需求時,就先從內存池中分配內存給這個需求,不夠了再申請新的內存。這樣做最顯著的優勢就是能夠減少內存碎片,提升效率

Python中的內存管理機制--pymalloc python中的內存管理機制都有兩套實現,一套是針對小對象,就是大小小於256bits時,pymalloc會在內存池中申請內存空間;當大於256bits,則會直接執行new/malloc的行爲來申請內存空間

25.當退出 Python 時是否釋放所有內存分配?

循環引用其它對象或引用自全局命名空間的對象的模塊,在python退出時並非完全釋放

26.正則表達式匹配中(.*)和(.*?)匹配區別?

(.*)是貪婪匹配,會把滿足正則的儘可能多的往後匹配

(.*?)是非貪婪匹配,會把滿足正則的儘可能少匹配

27.解釋一下 python 中 pass 語句的作用?

Python中pass是空語句,是爲了保持程序結構的完整性;pass不做任何事情,一般用做佔位語句;一般在搭建程序框架的時候或在判斷語句中使用

28.python 中的 is 和==

Is是身份運算符,判斷兩個對象的內存id是否相等

==是比較運算符,判斷兩個對象的值是否相等

進行值比較時使用==,判斷是否是同一對象時使用is

29.Python 中的作用域

L(Local)局部做用域

E(Enclosing)閉包函數外的函數中

G(Global)全局作用域

B(Built-in)內建作用域

以L->E->G->B的規則查找,即:在局部找不到,便會去局部外的局部找(例如閉包),再找不到就會去全局找,再者去內建中找

30.copy 和 deepcopy 的區別是什麼?

Copy僅拷貝對象本身,而不拷貝對象中應用的其他對象

Deepcopy除拷貝對象本身,而且拷貝對象中引用的其他對象

Copy不會爲子對象額外創建新的內存空間,而子對象被修改之後,這個子對象的引用都會發生改變;deepcopy是一個新對象的創建,只是用了和被拷貝對象相同的值,子對象改變不會影響被拷貝對象

31.代碼中經常遇到的*args, **kwargs 含義及用法。

Args是arguments的縮寫,表示位置參數

Kwargs是keyword arguments的縮寫,表示關鍵字參數

32.w、a+、wb 文件寫入模式的區別

r:讀取文件,若文件不存在則會報錯

w:寫入文件,若文件不存在則會先創建再寫入,會覆蓋原文件

a:寫入文件,若文件不存在則會先創建再寫入,但不會覆蓋原文件,而是追加在文件末尾

rb,wb:分別於r,w類似,用於讀寫二進制文件

r+:可讀、可寫,文件不存在也會報錯,寫操作時會覆蓋

w+:可讀、可寫,文件不存在先創建,會覆蓋

a+:可讀、可寫,文件不存在先創建,不會覆蓋,追加在末尾

33.已知:AList = [1,2,3] BSet = {1,2,3}

(1) 從 AList 和 BSet 中 查找 4,最壞時間複雜度那個大?
(2) 從 AList 和 BSet 中 插入 4,最壞時間複雜度那個大?

Python的列表內部實現是數組(具體實現要看解析器,CPython的實現),因此就有數組的特點。超過容量會增加更多的容量,set,get是O(1),但del,insert,in的性能是O(n).

關於字典需要了解的是hash函數和哈希桶。一個好的hash函數使到哈希桶中的值只有一個,若多個key hash到了同一個哈希桶中,稱之爲哈希衝突。查找值時,會先定位到哈希桶中,再遍歷hash桶。在hash基本沒有衝突的情況下get,set,delete,in方面都是O(1)。

集合內部實現是dict的。在in操作上是O(1),這點比list要強

由此可見:(1)查找操作set優於list;(2)插入操作兩個相同

34.TCP 和 UDP 的區別?

1.基於連接與無連接;
2.對系統資源的要求(TCP較多,UDP少);

3.UDP程序結構較簡單;
4.流模式與數據報模式 ;

5.TCP保證數據正確性,UDP可能丟包,TCP保證數據順序,UDP不保證

35.簡要介紹三次握手和四次揮手

(1)第一次握手:客戶端發送SYN包(SYN=j)到服務器,並進入SYN_SEND狀態,等待服務器確認

(2)第二次握手:服務器收到SYN包,必須確認客戶的SYN(ACK=j+1),同時自己也發送一個SYN包(SYN=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態。

(3)第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ACK=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。

完成三次握手,客戶端與服務器開始傳送數據

由於TCP連接是全雙工的,連接的拆除需要發送四個包,因此稱爲“四次揮手”。客戶端或服務器均可主動發起揮手動作,在socket編程中,任何一方執行close()操作即可產生揮手操作。

(1)第一次揮手:客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送。 

(2)第二次揮手:服務器收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1。

(3)第三次揮手:服務器關閉與客戶端的連接,發送一個FIN給客戶端。 

(4)第四次揮手:客戶端發回ACK報文確認,並將確認序號設置爲收到序號加1

36.什麼是粘包? socket 中造成粘包的原因是什麼? 哪些情況會發生粘包現象?

概念:粘包:多個數據包被連續存儲於連續的緩存中,在對數據包進行讀取時由於無法確定發生方的發送邊界,而採用某一估測值大小來進行數據讀出,若雙方的size不一致時就會使指發送方發送的若干包數據到接收方接收時粘成一包,從接收緩衝區看,後一包數據的頭緊接着前一包數據的尾

出現粘包的原因:出現粘包現象的原因是多方面的,它既可能由發送方造成,也可能由接收方造成

發送方引起的粘包是由TCP協議本身造成的,TCP爲提高傳輸效率,發送方往往要收集到足夠多的數據後才發送一包數據。若連續幾次發送的數據都很少,通常TCP會根據優化算法把這些數據合成一包後一次發送出去,這樣接收方就收到了粘包數據

接收方引起的粘包是由於接收方用戶進程不及時接收數據,從而導致粘包現象。這是因爲接收方先把收到的數據放在系統接收緩衝區,用戶進程從該緩衝區取數據,若下一包數據到達時前一包數據尚未被用戶進程取走,則下一包數據放到系統接收緩衝區時就接到前一包數據之後,而用戶進程根據預先設定的緩衝區大小從系統接收緩衝區取數據,這樣就一次取到了多包數據

粘包的處理方式:(1)當時短連接的情況下,不用考慮粘包的情況(2)如果發送數據無結構,如文件傳輸,這樣發送方只管發送,接收方只什麼是粘包? socket 中造成粘包的原因是什麼? 哪些情況會發生粘包現象? 併發 概念:粘包:多個數據包被連續存儲於連續的緩存中,在對數據包進行讀取時由於無法確定發生方的發送邊界,而採用某一估測值大小來進行數據讀出,若雙方的size不一致時就會使指發送方發送的若干包數據到接收方接收時粘成一包,從接收緩衝區看,後一包數據的頭緊接着前一包數據的尾 出現粘包的原因:出現粘包現象的原因是多方面的,它既可能由發送方造成,也可能由接收方造成 發送方引起的粘包是由TCP協議本身造成的,TCP爲提高傳輸效率,發送方往往要收集到足夠多的數據後才發送一包數據。若連續幾次發送的數據都很少,通常TCP會根據優化算法把這些數據合成一包後一次發送出去,這樣接收方就收到了粘包數據 接收方引起的粘包是由於接收方用戶進程不及時接收數據,從而導致粘包現象。這是因爲接收方先把收到的數據放在系統接收緩衝區,用戶進程從該緩衝區取數據,若下一包數據到達時前一包數據尚未被用戶進程取走,則下一包數據放到系統接收緩衝區時就接到前一包數據之後,而用戶進程根據預先設定的緩衝區大小從系統接收緩衝區取數據,這樣就一次取到了多包數據 粘包的處理方式:(1)當時短連接的情況下,不用考慮粘包的情況(2)如果發送數據無結構,如文件傳輸,這樣發送方只管發送,接收方只管接收存儲就ok,也不用考慮粘包(3)如果雙方建立長連接,需要在連接後一段時間內發送不同結構數據 接收方創建預處理線程,對接收到的數據包進行預處理,將粘連的包分開; 分包是指在出現粘包的時候我們的接收方要進行分包處理。(在長連接中都會出現) 數據包的邊界發生錯位,導致讀出錯誤的數據分包,進而曲解原始數據含義。 粘包情況有兩種,一種是粘在一起的包都是完整的數據包,另一種情況是粘在一起的包有不完整的包管接收存儲就ok,也不用考慮粘包(3)如果雙方建立長連接,需要在連接後一段時間內發送不同結構數據

接收方創建預處理線程,對接收到的數據包進行預處理,將粘連的包分開;

分包是指在出現粘包的時候我們的接收方要進行分包處理。(在長連接中都會出現) 數據包的邊界發生錯位,導致讀出錯誤的數據分包,進而曲解原始數據含義。

粘包情況有兩種,一種是粘在一起的包都是完整的數據包,另一種情況是粘在一起的包有不完整的包

37.簡述 GIL

GIL 是python的全局解釋器鎖,同一進程中假如有多個線程運行,一個線程在運行python程序的時候會霸佔python解釋器(加了一把鎖即GIL),使該進程內的其他線程無法運行,等該線程運行完後其他線程才能運行。如果線程運行過程中遇到耗時操作,則解釋器鎖解開,使其他線程運行。所以在多線程中,線程的運行仍是有先後順序的,並不是同時進行。

多進程中因爲每個進程都能被系統分配資源,相當於每個進程有了一個python解釋器,所以多進程可以實現多個進程的同時運行,缺點是進程系統資源開銷大

38.IO 多路複用的作用?

I/O多路複用實際上就是用select, poll, epoll監聽多個io對象,當io對象有變化(有數據)的時候就通知用戶進程。好處就是單個進程可以處理多個socket

39.select、poll、epoll 模型的區別?

select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作

(1)select==>時間複雜度O(n)

它僅僅知道了,有I/O事件發生了,卻並不知道是哪那幾個流(可能有一個,多個,甚至全部),我們只能無差別輪詢所有流,找出能讀出數據,或者寫入數據的流,對他們進行操作。所以select具有O(n)的無差別輪詢複雜度,同時處理的流越多,無差別輪詢時間就越長。

select本質上是通過設置或者檢查存放fd標誌位的數據結構來進行下一步處理。這樣所帶來的缺點是:

1、 單個進程可監視的fd數量被限制,即能監聽端口的大小有限。

      一般來說這個數目和系統內存關係很大,具體數目可以cat /proc/sys/fs/file-max察看。32位機默認是1024個。64位機默認是2048.

2、 對socket進行掃描時是線性掃描,即採用輪詢的方法,效率較低:

       當套接字比較多的時候,每次select()都要通過遍歷FD_SETSIZE個Socket來完成調度,不管哪個Socket是活躍的,都遍歷一遍。這會浪費很多CPU時間。如果能給套接字註冊某個回調函數,當他們活躍時,自動完成相關操作,那就避免了輪詢,這正是epoll與kqueue做的。

3、需要維護一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時複製開銷大

(2)poll==>時間複雜度O(n)

poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然後查詢每個fd對應的設備狀態, 如果設備就緒則在設備等待隊列中加入一項並繼續遍歷,如果遍歷完所有fd後沒有發現就緒設備,則掛起當前進程,直到設備就緒或者主動超時,被喚醒後它又要再次遍歷fd。這個過程經歷了多次無謂的遍歷。

但是它沒有最大連接數的限制,原因是它是基於鏈表來存儲的.但是同樣有一個缺點:

1、大量的fd的數組被整體複製於用戶態和內核地址空間之間,而不管這樣的複製是不是有意義。                   

2、poll還有一個特點是“水平觸發”,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd。

(3)epoll==>時間複雜度O(1)

epoll可以理解爲event poll,不同於忙輪詢和無差別輪詢,epoll會把哪個流發生了怎樣的I/O事件通知我們。所以我們說epoll實際上是事件驅動(每個事件關聯上fd)的,此時我們對這些流的操作都是有意義的。(複雜度降低到了O(1))

epoll有EPOLLLT和EPOLLET兩種觸發模式,LT是默認的模式,ET是“高速”模式。LT模式下,只要這個fd還有數據可讀,每次 epoll_wait都會返回它的事件,提醒用戶程序去操作,而在ET(邊緣觸發)模式中,它只會提示一次,直到下次再有數據流入之前都不會再提示了,無 論fd中是否還有數據可讀。所以在ET模式下,read一個fd的時候一定要把它的buffer讀光,也就是說一直讀到read的返回值小於請求值,或者 遇到EAGAIN錯誤。還有一個特點是,epoll使用“事件”的就緒通知方式,通過epoll_ctl註冊fd,一旦該fd就緒,內核就會採用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知。

epoll爲什麼要有EPOLLET觸發模式?

如果採用EPOLLLT模式的話,系統中一旦有大量你不需要讀寫的就緒文件描述符,它們每次調用epoll_wait都會返回,這樣會大大降低處理程序檢索自己關心的就緒文件描述符的效率.。而採用EPOLLET這種邊沿觸發模式的話,當被監控的文件描述符上有可讀寫事件發生時,epoll_wait()會通知處理程序去讀寫。如果這次沒有把數據全部讀寫完(如讀寫緩衝區太小),那麼下次調用epoll_wait()時,它不會通知你,也就是它只會通知你一次,直到該文件描述符上出現第二次可讀寫事件纔會通知你!!!這種模式比水平觸發效率高,系統不會充斥大量你不關心的就緒文件描述符

epoll的優點:

1、沒有最大併發連接的限制,能打開的FD的上限遠大於1024(1G的內存上能監聽約10萬個端口);
2、效率提升,不是輪詢的方式,不會隨着FD數目的增加效率下降。只有活躍可用的FD纔會調用callback函數;
即Epoll最大的優點就在於它只管你“活躍”的連接,而跟連接總數無關,因此在實際的網絡環境中,Epoll的效率就會遠遠高於select和poll。

3、 內存拷貝,利用mmap()文件映射內存加速與內核空間的消息傳遞;即epoll使用mmap減少複製開銷

總結:

1、支持一個進程所能打開的最大連接數

Select:單個進程所能打開的最大連接數有FD_SETSIZE宏定義,其大小是32個整數的大小(在32位的機器上,大小就是3232,同理64位機器上FD_SETSIZE爲3264),當然我們可以對進行修改,然後重新編譯內核,但是性能可能會受到影響,這需要進一步的測試。

Poll:poll本質上和select沒有區別,但是它沒有最大連接數的限制,原因是它是基於鏈表來存儲的

Epoll:雖然連接數有上限,但是很大,1G內存的機器上可以打開10萬左右的連接,2G內存的機器能打開20萬左右的連接

2、FD劇增後帶來的IO效率問題

Select:因爲每次調用時都會對連接進行線性遍歷,所以隨着FD的增加會造成遍歷速度慢的“線性下降性能問題”。

Poll:同上

Epoll:因爲epoll內核中實現是根據每個fd上的callback函數來實現的,只有活躍的socket纔會主動調用callback,所以在活躍socket較少的情況下,使用epoll沒有前面兩者的線性下降的性能問題,但是所有socket都很活躍的情況下,可能會有性能問題。

3、 消息傳遞方式

Select:內核需要將消息傳遞到用戶空間,都需要內核拷貝動作

Poll:同上

Epoll:epoll通過內核和用戶空間共享一塊內存來實現的。

40.什麼是併發和並行?

並行(parallel):指在同一時刻,有多條指令在多個處理器上同時執行。所以無論從微觀還是從宏觀來看,二者都是一起執行的。

併發(concurrency):指在同一時刻只能有一條指令執行,但多個進程指令被快速的輪換執行,使得在宏觀上具有多個進程同時執行的效果,但在微觀上並不是同時執行的,只是把時間分成若干段,使多個進程快速交替的執行。

並行在多處理器系統中存在,而併發可以在單處理器和多處理器系統中都存在,併發能夠在單處理器系統中存在是因爲併發是並行的假象,並行要求程序能夠同時執行多個操作,而併發只是要求程序假裝同時執行多個操作(每個小時間片執行一個操作,多個操作快速切換執行)。

當有多個線程在操作時,如果系統只有一個 CPU,則它根本不可能真正同時進行一個以上的線程,它只能把 CPU 運行時間劃分成若干個時間段,再將時間段分配給各個線程執行,在一個時間段的線程代碼運行時,其它線程處於掛起狀態.這種方式我們稱之爲併發(Concurrent)。

當系統有一個以上 CPU 時,則線程的操作有可能非併發。當一個 CPU 執行一個線程時,另一個 CPU 可以執行另一個線程,兩個線程互不搶佔 CPU 資源,可以同時進行,這種方式我們稱之爲並行(Parallel)

41.解釋什麼是異步非阻塞?

 同步異步是針對調用者來說的,調用者發起一個請求後,一直乾等被調用者的反饋就是同步,不必等去做別的事就是異步。

 阻塞非阻塞是針對被調用者來說的,被調用者收到一個請求後,做完請求任務後纔給出反饋就是阻塞,收到請求直接給出反饋再去做任務就是非阻塞。

42.threading.local 的作用?

threading.local()這個方法的特點用來保存一個全局變量,但是這個全局變量只有在當前線程才能訪問,如果你在開發多線程應用的時候 需要每個線程保存一個單獨的數據供當前線程操作,可以考慮使用這個方法,簡單有效。舉例:每個子線程使用全局對象a,但每個線程定義的屬性a.xx是該線程獨有的,Python提供了 threading.local 類,將這個類實例化得到一個全局對象,但是不同的線程使用這個對象存儲的數據其它線程不可見(本質上就是不同的線程使用這個對象時爲其創建一個獨立的字典)。

43.git 如何查看某次提交修改的內容

1、首先,需要通過git log打印所有commit記錄

2、找到你想查看的那次commit的commitid。

3、查看修改。git show commitId

4、看某次commit中具體某個文件的修改:git show commitId fileName

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章