python 面試題(進階)


106.進程總結

進程:程序運行在操作系統上的一個實例,就稱之為進程。進程需要相應的系統資源:內存、時間片、pid。 創建進程: 首先要導入multiprocessing中的Process: 創建一個Process對象; 創建Process對象時,可以傳遞參數;

p = Process(target=XXX,args=(tuple,),kwargs={key:value}) target = XXX 指定的任務函數,不用加(), args=(tuple,)kwargs={key:value}給任務函數傳遞的參數

使用start()啟動進程 結束進程 給子進程指定函數傳遞參數Demo

import os from mulitprocessing import Process import time def pro_func(name,age,**kwargs): for i in range(5): print("子進程正在運行中,name=%s,age=%d,pid=%d"%(name,age,os.getpid())) print(kwargs) time.sleep(0.2) if __name__ =="__main__": #創建Process對象 p = Process(target=pro_func,args=('小明',18),kwargs={'m':20}) #啟動進程 p.start() time.sleep(1) #1秒鍾之后,立刻結束子進程 p.terminate() p.join()

注意:進程間不共享全局變量

進程之間的通信-Queue

在初始化Queue()對象時(例如q=Queue(),若在括號中沒有指定最大可接受的消息數量,獲數量為負值時,那么就代表可接受的消息數量沒有上限一直到內存盡頭)

Queue.qsize():返回當前隊列包含的消息數量

Queue.empty():如果隊列為空,返回True,反之False

Queue.full():如果隊列滿了,返回True,反之False

Queue.get([block[,timeout]]):獲取隊列中的一條消息,然后將其從隊列中移除,

block默認值為True。

如果block使用默認值,且沒有設置timeout(單位秒),消息隊列如果為空,此時程序將被阻塞(停在讀中狀態),直到消息隊列讀到消息為止,如果設置了timeout,則會等待timeout秒,若還沒讀取到任何消息,則拋出“Queue.Empty"異常:

Queue.get_nowait()相當於Queue.get(False)

Queue.put(item,[block[,timeout]]):將item消息寫入隊列,block默認值為True; 如果block使用默認值,且沒有設置timeout(單位秒),消息隊列如果已經沒有空間可寫入,此時程序將被阻塞(停在寫入狀態),直到從消息隊列騰出空間為止,如果設置了timeout,則會等待timeout秒,若還沒空間,則拋出”Queue.Full"異常 如果block值為False,消息隊列如果沒有空間可寫入,則會立刻拋出"Queue.Full"異常; Queue.put_nowait(item):相當Queue.put(item,False)

進程間通信Demo:

from multiprocessing import Process.Queue import os,time,random #寫數據進程執行的代碼: def write(q): for value in ['A','B','C']: print("Put %s to queue...",%value) q.put(value) time.sleep(random.random()) #讀數據進程執行的代碼 def read(q): while True: if not q.empty(): value = q.get(True) print("Get %s from queue.",%value) time.sleep(random.random()) else: break if __name__=='__main__': #父進程創建Queue,並傳給各個子進程 q = Queue() pw = Process(target=write,args=(q,)) pr = Process(target=read,args=(q,)) #啟動子進程pw ,寫入: pw.start() #等待pw結束 pw.join() #啟動子進程pr,讀取: pr.start() pr.join() #pr 進程里是死循環,無法等待其結束,只能強行終止: print('') print('所有數據都寫入並且讀完')
進程池Pool
#coding:utf-8
from multiprocessing import Pool import os,time,random def worker(msg): t_start = time.time() print("%s 開始執行,進程號為%d"%(msg,os.getpid())) # random.random()隨機生成0-1之間的浮點數 time.sleep(random.random()*2) t_stop = time.time() print(msg,"執行完畢,耗時%0.2f”%(t_stop-t_start)) po = Pool(3)#定義一個進程池,最大進程數3 for i in range(0,10): po.apply_async(worker,(i,)) print("---start----") po.close() po.join() print("----end----")

進程池中使用Queue

如果要使用Pool創建進程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否則會得到如下的錯誤信息:

RuntimeError: Queue objects should only be shared between processs through inheritance

from multiprocessing import Manager,Pool import os,time,random def reader(q): print("reader 啟動(%s),父進程為(%s)"%(os.getpid(),os.getpid())) for i in range(q.qsize()): print("reader 從Queue獲取到消息:%s"%q.get(True)) def writer(q): print("writer 啟動(%s),父進程為(%s)"%(os.getpid(),os.getpid())) for i ini "itcast": q.put(i) if __name__ == "__main__": print("(%s)start"%os.getpid()) q = Manager().Queue()#使用Manager中的Queue po = Pool() po.apply_async(wrtier,(q,)) time.sleep(1) po.apply_async(reader,(q,)) po.close() po.join() print("(%s)End"%os.getpid())

107.談談你對多進程,多線程,以及協程的理解,項目是否用?

這個問題被問的概念相當之大, 進程:一個運行的程序(代碼)就是一個進程,沒有運行的代碼叫程序,進程是系統資源分配的最小單位,進程擁有自己獨立的內存空間,所有進程間數據不共享,開銷大。

線程: cpu調度執行的最小單位,也叫執行路徑,不能獨立存在,依賴進程存在,一個進程至少有一個線程,叫主線程,而多個線程共享內存(數據共享,共享全局變量),從而極大地提高了程序的運行效率。

協程: 是一種用戶態的輕量級線程,協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧。協程調度時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操中棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。

108.Python異步使用場景有那些?

異步的使用場景:

1、 不涉及共享資源,獲對共享資源只讀,即非互斥操作

2、 沒有時序上的嚴格關系

3、 不需要原子操作,或可以通過其他方式控制原子性

4、 常用於IO操作等耗時操作,因為比較影響客戶體驗和使用性能

5、 不影響主線程邏輯

109.多線程共同操作同一個數據互斥鎖同步?

import threading import time class MyThread(threading.Thread): def run(self): global num time.sleep(1) if mutex.acquire(1): num +=1 msg = self.name + 'set num to ' +str(num) print msg mutex.release() num = 0 mutex = threading.Lock() def test(): for i in range(5): t = MyThread() t.start() if __name__=="__main__": test()

110.什么是多線程競爭?

線程是非獨立的,同一個進程里線程是數據共享的,當各個線程訪問數據資源時會出現競爭狀態即:數據幾乎同步會被多個線程占用,造成數據混亂,即所謂的線程不安全

那么怎么解決多線程競爭問題?---鎖

鎖的好處: 確保了某段關鍵代碼(共享數據資源)只能由一個線程從頭到尾完整地執行能解決多線程資源競爭下的原子操作問題。

鎖的壞處: 阻止了多線程並發執行,包含鎖的某段代碼實際上只能以單線程模式執行,效率就大大地下降了

鎖的致命問題: 死鎖

111.請介紹一下Python的線程同步?

一、 setDaemon(False) 當一個進程啟動之后,會默認產生一個主線程,因為線程是程序執行的最小單位,當設置多線程時,主線程會創建多個子線程,在Python中,默認情況下就是setDaemon(False),主線程執行完自己的任務以后,就退出了,此時子線程會繼續執行自己的任務,直到自己的任務結束。

例子

import threading import time def thread(): time.sleep(2) print('---子線程結束---') def main(): t1 = threading.Thread(target=thread) t1.start() print('---主線程--結束') if __name__ =='__main__': main() #執行結果 ---主線程--結束 ---子線程結束---

二、 setDaemon(True) 當我們使用setDaemon(True)時,這是子線程為守護線程,主線程一旦執行結束,則全部子線程被強制終止

例子

import threading import time def thread(): time.sleep(2) print(’---子線程結束---') def main(): t1 = threading.Thread(target=thread) t1.setDaemon(True)#設置子線程守護主線程 t1.start() print('---主線程結束---') if __name__ =='__main__': main() #執行結果 ---主線程結束--- #只有主線程結束,子線程來不及執行就被強制結束

三、 join(線程同步) join 所完成的工作就是線程同步,即主線程任務結束以后,進入堵塞狀態,一直等待所有的子線程結束以后,主線程再終止。

當設置守護線程時,含義是主線程對於子線程等待timeout的時間將會殺死該子線程,最后退出程序,所以說,如果有10個子線程,全部的等待時間就是每個timeout的累加和,簡單的來說,就是給每個子線程一個timeou的時間,讓他去執行,時間一到,不管任務有沒有完成,直接殺死。

沒有設置守護線程時,主線程將會等待timeout的累加和這樣的一段時間,時間一到,主線程結束,但是並沒有殺死子線程,子線程依然可以繼續執行,直到子線程全部結束,程序退出。

例子

import threading import time def thread(): time.sleep(2) print('---子線程結束---') def main(): t1 = threading.Thread(target=thread) t1.setDaemon(True) t1.start() t1.join(timeout=1)#1 線程同步,主線程堵塞1s 然后主線程結束,子線程繼續執行 #2 如果不設置timeout參數就等子線程結束主線程再結束 #3 如果設置了setDaemon=True和timeout=1主線程等待1s后會強制殺死子線程,然后主線程結束 print('---主線程結束---') if __name__=='__main___': main()

112.解釋以下什么是鎖,有哪幾種鎖?

鎖(Lock)是python提供的對線程控制的對象。有互斥鎖,可重入鎖,死鎖。

113.什么是死鎖?

若干子線程在系統資源競爭時,都在等待對方對某部分資源解除占用狀態,結果是誰也不願先解鎖,互相干等着,程序無法執行下去,這就是死鎖。

GIL鎖 全局解釋器鎖

作用: 限制多線程同時執行,保證同一時間只有一個線程執行,所以cython里的多線程其實是偽多線程!

所以python里常常使用協程技術來代替多線程,協程是一種更輕量級的線程。

進程和線程的切換時由系統決定,而協程由我們程序員自己決定,而模塊gevent下切換是遇到了耗時操作時才會切換

三者的關系:進程里有線程,線程里有協程。

114.多線程交互訪問數據,如果訪問到了就不訪問了?

怎么避免重讀?

創建一個已訪問數據列表,用於存儲已經訪問過的數據,並加上互斥鎖,在多線程訪問數據的時候先查看數據是否在已訪問的列表中,若已存在就直接跳過。

115.什么是線程安全,什么是互斥鎖?

每個對象都對應於一個可稱為’互斥鎖‘的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象。

同一進程中的多線程之間是共享系統資源的,多個線程同時對一個對象進行操作,一個線程操作尚未結束,另一線程已經對其進行操作,導致最終結果出現錯誤,此時需要對被操作對象添加互斥鎖,保證每個線程對該對象的操作都得到正確的結果。

116.說說下面幾個概念:同步,異步,阻塞,非阻塞?

同步: 多個任務之間有先后順序執行,一個執行完下個才能執行。

異步: 多個任務之間沒有先后順序,可以同時執行,有時候一個任務可能要在必要的時候獲取另一個同時執行的任務的結果,這個就叫回調!

阻塞: 如果卡住了調用者,調用者不能繼續往下執行,就是說調用者阻塞了。

非阻塞: 如果不會卡住,可以繼續執行,就是說非阻塞的。

同步異步相對於多任務而言,阻塞非阻塞相對於代碼執行而言。

117.什么是僵屍進程和孤兒進程?怎么避免僵屍進程?

孤兒進程: 父進程退出,子進程還在運行的這些子進程都是孤兒進程,孤兒進程將被init 進程(進程號為1)所收養,並由init 進程對他們完成狀態收集工作。

僵屍進程: 進程使用fork 創建子進程,如果子進程退出,而父進程並沒有調用wait 獲waitpid 獲取子進程的狀態信息,那么子進程的進程描述符仍然保存在系統中的這些進程是僵屍進程。

避免僵屍進程的方法:

1.fork 兩次用孫子進程去完成子進程的任務

2.用wait()函數使父進程阻塞

3.使用信號量,在signal handler 中調用waitpid,這樣父進程不用阻塞

118.python中進程與線程的使用場景?

多進程適合在CPU密集操作(cpu操作指令比較多,如位多的的浮點運算)。

多線程適合在IO密性型操作(讀寫數據操作比多的的,比如爬蟲)

119.線程是並發還是並行,進程是並發還是並行?

線程是並發,進程是並行;

進程之間互相獨立,是系統分配資源的最小單位,同一個線程中的所有線程共享資源。

120.並行(parallel)和並發(concurrency)?

並行: 同一時刻多個任務同時在運行

不會在同一時刻同時運行,存在交替執行的情況。

實現並行的庫有: multiprocessing

實現並發的庫有: threading

程序需要執行較多的讀寫、請求和回復任務的需要大量的IO操作,IO密集型操作使用並發更好。

CPU運算量大的程序,使用並行會更好

121.IO密集型和CPU密集型區別?

IO密集型: 系統運行,大部分的狀況是CPU在等 I/O(硬盤/內存)的讀/寫

CPU密集型: 大部分時間用來做計算,邏輯判斷等CPU動作的程序稱之CPU密集型。

122.python asyncio的原理?

asyncio這個庫就是使用python的yield這個可以打斷保存當前函數的上下文的機制, 封裝好了selector 擺脫掉了復雜的回調關系

網絡編程

123.怎么實現強行關閉客戶端和服務器之間的連接?

124.簡述TCP和UDP的區別以及優缺點?

125.簡述瀏覽器通過WSGI請求動態資源的過程?

瀏覽器發送的請求被Nginx監聽到,Nginx根據請求的URL的PATH或者后綴把請求靜態資源的分發到靜態資源的目錄,別的請求根據配置好的轉發到相應端口。 實現了WSGI的程序會監聽某個端口,監聽到Nginx轉發過來的請求接收后(一般用socket的recv來接收HTTP的報文)以后把請求的報文封裝成environ的字典對象,然后再提供一個start_response的方法。把這兩個對象當成參數傳入某個方法比如wsgi_app(environ, start_response)或者實現了__call__(self, environ, start_response)方法的某個實例。這個實例再調用start_response返回給實現了WSGI的中間件,再由中間件返回給Nginx。

126.描述用瀏覽器訪問www.baidu.com的過程

127.Post和Get請求的區別?

128.cookie 和session 的區別?

129.列出你知道的HTTP協議的狀態碼,說出表示什么意思?

130.請簡單說一下三次握手和四次揮手?

131.說一下什么是tcp的2MSL?

132.為什么客戶端在TIME-WAIT狀態必須等待2MSL的時間?

133.說說HTTP和HTTPS區別?

134.談一下HTTP協議以及協議頭部中表示數據類型的字段?

135.HTTP請求方法都有什么?

136.使用Socket套接字需要傳入哪些參數 ?

137.HTTP常見請求頭?

138.七層模型?

139.url的形式?

Web

Flask

140.對Flask藍圖(Blueprint)的理解?

藍圖的定義

藍圖 /Blueprint 是Flask應用程序組件化的方法,可以在一個應用內或跨越多個項目共用藍圖。使用藍圖可以極大簡化大型應用的開發難度,也為Flask擴展提供了一種在應用中注冊服務的集中式機制。

藍圖的應用場景:

把一個應用分解為一個藍圖的集合。這對大型應用是理想的。一個項目可以實例化一個應用對象,初始化幾個擴展,並注冊一集合的藍圖。

以URL前綴和/或子域名,在應用上注冊一個藍圖。URL前綴/子域名中的參數即成為這個藍圖下的所有視圖函數的共同的視圖參數(默認情況下) 在一個應用中用不同的URL規則多次注冊一個藍圖。

通過藍圖提供模板過濾器、靜態文件、模板和其他功能。一個藍圖不一定要實現應用或視圖函數。

初始化一個Flask擴展時,在這些情況中注冊一個藍圖。

藍圖的缺點:

不能在應用創建后撤銷注冊一個藍圖而不銷毀整個應用對象。

使用藍圖的三個步驟

1.創建一個藍圖對象

blue = Blueprint("blue",__name__)

2.在這個藍圖對象上進行操作,例如注冊路由、指定靜態文件夾、注冊模板過濾器...

@blue.route('/') def blue_index(): return "Welcome to my blueprint"

3.在應用對象上注冊這個藍圖對象

app.register_blueprint(blue,url_prefix="/blue")

141.Flask 和 Django 路由映射的區別?

在django中,路由是瀏覽器訪問服務器時,先訪問的項目中的url,再由項目中的url找到應用中url,這些url是放在一個列表里,遵從從前往后匹配的規則。在flask中,路由是通過裝飾器給每個視圖函數提供的,而且根據請求方式的不同可以一個url用於不同的作用。

Django

142.什么是wsgi,uwsgi,uWSGI?

WSGI:

web服務器網關接口,是一套協議。用於接收用戶請求並將請求進行初次封裝,然后將請求交給web框架。

實現wsgi協議的模塊:wsgiref,本質上就是編寫一socket服務端,用於接收用戶請求(django)

werkzeug,本質上就是編寫一個socket服務端,用於接收用戶請求(flask)

uwsgi:

與WSGI一樣是一種通信協議,它是uWSGI服務器的獨占協議,用於定義傳輸信息的類型。 uWSGI:

是一個web服務器,實現了WSGI的協議,uWSGI協議,http協議

143.Django、Flask、Tornado的對比?

1、 Django走的大而全的方向,開發效率高。它的MTV框架,自帶的ORM,admin后台管理,自帶的sqlite數據庫和開發測試用的服務器,給開發者提高了超高的開發效率。 重量級web框架,功能齊全,提供一站式解決的思路,能讓開發者不用在選擇上花費大量時間。

自帶ORM和模板引擎,支持jinja等非官方模板引擎。

自帶ORM使Django和關系型數據庫耦合度高,如果要使用非關系型數據庫,需要使用第三方庫

自帶數據庫管理app

成熟,穩定,開發效率高,相對於Flask,Django的整體封閉性比較好,適合做企業級網站的開發。python web框架的先驅,第三方庫豐富

2、 Flask 是輕量級的框架,自由,靈活,可擴展性強,核心基於Werkzeug WSGI工具 和jinja2 模板引擎

適用於做小網站以及web服務的API,開發大型網站無壓力,但架構需要自己設計

與關系型數據庫的結合不弱於Django,而與非關系型數據庫的結合遠遠優於Django

3、 Tornado走的是少而精的方向,性能優越,它最出名的異步非阻塞的設計方式

Tornado的兩大核心模塊:

iostraem:對非阻塞的socket進行簡單的封裝

ioloop: 對I/O 多路復用的封裝,它實現一個單例

144.CORS 和 CSRF的區別?

什么是CORS?

CORS是一個W3C標准,全稱是“跨域資源共享"(Cross-origin resoure sharing). 它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而客服了AJAX只能同源使用的限制。

什么是CSRF?

CSRF主流防御方式是在后端生成表單的時候生成一串隨機token,內置到表單里成為一個字段,同時,將此串token置入session中。每次表單提交到后端時都會檢查這兩個值是否一致,以此來判斷此次表單提交是否是可信的,提交過一次之后,如果這個頁面沒有生成CSRF token,那么token將會被清空,如果有新的需求,那么token會被更新。 攻擊者可以偽造POST表單提交,但是他沒有后端生成的內置於表單的token,session中沒有token都無濟於事。

145.Session,Cookie,JWT的理解

為什么要使用會話管理

眾所周知,HTTP協議是一個無狀態的協議,也就是說每個請求都是一個獨立的請求,請求與請求之間並無關系。但在實際的應用場景,這種方式並不能滿足我們的需求。舉個大家都喜歡用的例子,把商品加入購物車,單獨考慮這個請求,服務端並不知道這個商品是誰的,應該加入誰的購物車?因此這個請求的上下文環境實際上應該包含用戶的相關信息,在每次用戶發出請求時把這一小部分額外信息,也做為請求的一部分,這樣服務端就可以根據上下文中的信息,針對具體的用戶進行操作。所以這幾種技術的出現都是對HTTP協議的一個補充,使得我們可以用HTTP協議+狀態管理構建一個的面向用戶的WEB應用。

Session 和Cookie的區別

這里我想先談談session與cookies,因為這兩個技術是做為開發最為常見的。那么session與cookies的區別是什么?個人認為session與cookies最核心區別在於額外信息由誰來維護。利用cookies來實現會話管理時,用戶的相關信息或者其他我們想要保持在每個請求中的信息,都是放在cookies中,而cookies是由客戶端來保存,每當客戶端發出新請求時,就會稍帶上cookies,服務端會根據其中的信息進行操作。 當利用session來進行會話管理時,客戶端實際上只存了一個由服務端發送的session_id,而由這個session_id,可以在服務端還原出所需要的所有狀態信息,從這里可以看出這部分信息是由服務端來維護的。

除此以外,session與cookies都有一些自己的缺點:

cookies的安全性不好,攻擊者可以通過獲取本地cookies進行欺騙或者利用cookies進行CSRF攻擊。使用cookies時,在多個域名下,會存在跨域問題。 session 在一定的時間里,需要存放在服務端,因此當擁有大量用戶時,也會大幅度降低服務端的性能,當有多台機器時,如何共享session也會是一個問題.(redis集群)也就是說,用戶第一個訪問的時候是服務器A,而第二個請求被轉發給了服務器B,那服務器B如何得知其狀態。實際上,session與cookies是有聯系的,比如我們可以把session_id存放在cookies中的。

JWT是如何工作的

首先用戶發出登錄請求,服務端根據用戶的登錄請求進行匹配,如果匹配成功,將相關的信息放入payload中,利用算法,加上服務端的密鑰生成token,這里需要注意的是secret_key很重要,如果這個泄露的話,客戶端就可以隨機篡改發送的額外信息,它是信息完整性的保證。生成token后服務端將其返回給客戶端,客戶端可以在下次請求時,將token一起交給服務端,一般是說我們可以將其放在Authorization首部中,這樣也就可以避免跨域問題。

146.簡述Django請求生命周期

一般是用戶通過瀏覽器向我們的服務器發起一個請求(request),這個請求會去訪問視圖函數,如果不涉及到數據調用,那么這個時候視圖函數返回一個模板也就是一個網頁給用戶) 視圖函數調用模型毛模型去數據庫查找數據,然后逐級返回,視圖函數把返回的數據填充到模板中空格中,最后返回網頁給用戶。

1.wsgi ,請求封裝后交給web框架(Flask,Django)

2.中間件,對請求進行校驗或在請求對象中添加其他相關數據,例如:csrf,request.session

3.路由匹配 根據瀏覽器發送的不同url去匹配不同的視圖函數

4.視圖函數,在視圖函數中進行業務邏輯的處理,可能涉及到:orm,templates

5.中間件,對響應的數據進行處理

6.wsgi,將響應的內容發送給瀏覽器

147.用的restframework完成api發送時間時區

當前的問題是用django的rest framework模塊做一個get請求的發送時間以及時區信息的api

class getCurrenttime(APIView): def get(self,request): local_time = time.localtime() time_zone =settings.TIME_ZONE temp = {'localtime':local_time,'timezone':time_zone} return Response(temp)

148.nginx,tomcat,apach到都是什么?

Nginx(engine x)是一個高性能的HTTP和反向代理服務器,也是 一個IMAP/POP3/SMTP服務器,工作在OSI七層,負載的實現方式:輪詢,IP_HASH,fair,session_sticky. Apache HTTP Server是一個模塊化的服務器,源於NCSAhttpd服務器 Tomcat 服務器是一個免費的開放源代碼的Web應用服務器,屬於輕量級應用服務器,是開發和調試JSP程序的首選。

149.請給出你熟悉關系數據庫范式有哪些,有什么作用?

在進行數據庫的設計時,所遵循的一些規范,只要按照設計規范進行設計,就能設計出沒有數據冗余和數據維護異常的數據庫結構。

數據庫的設計的規范有很多,通常來說我們在設是數據庫時只要達到其中一些規范就可以了,這些規范又稱之為數據庫的三范式,一共有三條,也存在着其他范式,我們只要做到滿足前三個范式的要求,就能設陳出符合我們的數據庫了,我們也不能全部來按照范式的要求來做,還要考慮實際的業務使用情況,所以有時候也需要做一些違反范式的要求。 1.數據庫設計的第一范式(最基本),基本上所有數據庫的范式都是符合第一范式的,符合第一范式的表具有以下幾個特點:

數據庫表中的所有字段都只具有單一屬性,單一屬性的列是由基本的數據類型(整型,浮點型,字符型等)所構成的設計出來的表都是簡單的二比表

2.數據庫設計的第二范式(是在第一范式的基礎上設計的),要求一個表中只具有一個業務主鍵,也就是說符合第二范式的表中不能存在非主鍵列對只對部分主鍵的依賴關系

3.數據庫設計的第三范式,指每一個非主屬性既不部分依賴與也不傳遞依賴於業務主鍵,也就是第二范式的基礎上消除了非主屬性對主鍵的傳遞依賴

150.簡述QQ登陸過程

qq登錄,在我們的項目中分為了三個接口,

第一個接口是請求qq服務器返回一個qq登錄的界面;

第二個接口是通過掃碼或賬號登陸進行驗證,qq服務器返回給瀏覽器一個code和state,利用這個code通過本地服務器去向qq服務器獲取access_token覆返回給本地服務器,憑借access_token再向qq服務器獲取用戶的openid(openid用戶的唯一標識)

第三個接口是判斷用戶是否是第一次qq登錄,如果不是的話直接登錄返回的jwt-token給用戶,對沒有綁定過本網站的用戶,對openid進行加密生成token進行綁定

151.post 和 get的區別?

1.GET是從服務器上獲取數據,POST是向服務器傳送數據

2.在客戶端,GET方式在通過URL提交數據,數據在URL中可以看到,POST方式,數據放置在HTML——HEADER內提交

3.對於GET方式,服務器端用Request.QueryString獲取變量的值,對於POST方式,服務器端用Request.Form獲取提交的數據

152.項目中日志的作用

一、日志相關概念

1.日志是一種可以追蹤某些軟件運行時所發生事件的方法

2.軟件開發人員可以向他們的代碼中調用日志記錄相關的方法來表明發生了某些事情

3.一個事件可以用一個包含可選變量數據的消息來描述

4.此外,事件也有重要性的概念,這個重要性也可以被成為嚴重性級別(level)

二、日志的作用

1.通過log的分析,可以方便用戶了解系統或軟件、應用的運行情況;

2.如果你的應用log足夠豐富,可以分析以往用戶的操作行為、類型喜好,地域分布或其他更多信息;

3.如果一個應用的log同時也分了多個級別,那么可以很輕易地分析得到該應用的健康狀況,及時發現問題並快速定位、解決問題,補救損失。

4.簡單來講就是我們通過記錄和分析日志可以了解一個系統或軟件程序運行情況是否正常,也可以在應用程序出現故障時快速定位問題。不僅在開發中,在運維中日志也很重要,日志的作用也可以簡單。總結為以下幾點:

1.程序調試

2.了解軟件程序運行情況,是否正常

3,軟件程序運行故障分析與問題定位

4,如果應用的日志信息足夠詳細和豐富,還可以用來做用戶行為分析

153.django中間件的使用?

Django在中間件中預置了六個方法,這六個方法的區別在於不同的階段執行,對輸入或輸出進行干預,方法如下:

1.初始化:無需任何參數,服務器響應第一個請求的時候調用一次,用於確定是否啟用當前中間件

def __init__(): pass

2.處理請求前:在每個請求上調用,返回None或HttpResponse對象。

def process_request(request): pass

3.處理視圖前:在每個請求上調用,返回None或HttpResponse對象。

def process_view(request,view_func,view_args,view_kwargs): pass

4.處理模板響應前:在每個請求上調用,返回實現了render方法的響應對象。

def process_template_response(request,response): pass

5.處理響應后:所有響應返回瀏覽器之前被調用,在每個請求上調用,返回HttpResponse對象。

def process_response(request,response): pass

6.異常處理:當視圖拋出異常時調用,在每個請求上調用,返回一個HttpResponse對象。

def process_exception(request,exception): pass

154.談一下你對uWSGI和nginx的理解?

1.uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的作用是與uWSGI服務器進行交換。WSGI是一種Web服務器網關接口。它是一個Web服務器(如nginx,uWSGI等服務器)與web應用(如用Flask框架寫的程序)通信的一種規范。

要注意WSGI/uwsgi/uWSGI這三個概念的區分。

WSGI是一種通信協議。

uwsgi是一種線路協議而不是通信協議,在此常用於在uWSGI服務器與其他網絡服務器的數據通信。

uWSGI是實現了uwsgi和WSGI兩種協議的Web服務器。

nginx 是一個開源的高性能的HTTP服務器和反向代理:

1.作為web服務器,它處理靜態文件和索引文件效果非常高

2.它的設計非常注重效率,最大支持5萬個並發連接,但只占用很少的內存空間

3.穩定性高,配置簡潔。

4.強大的反向代理和負載均衡功能,平衡集群中各個服務器的負載壓力應用

155.Python中三大框架各自的應用場景?

django:主要是用來搞快速開發的,他的亮點就是快速開發,節約成本,,如果要實現高並發的話,就要對django進行二次開發,比如把整個笨重的框架給拆掉自己寫socket實現http的通信,底層用純c,c++寫提升效率,ORM框架給干掉,自己編寫封裝與數據庫交互的框架,ORM雖然面向對象來操作數據庫,但是它的效率很低,使用外鍵來聯系表與表之間的查詢; flask: 輕量級,主要是用來寫接口的一個框架,實現前后端分離,提考開發效率,Flask本身相當於一個內核,其他幾乎所有的功能都要用到擴展(郵件擴展Flask-Mail,用戶認證Flask-Login),都需要用第三方的擴展來實現。比如可以用Flask-extension加入ORM、文件上傳、身份驗證等。Flask沒有默認使用的數據庫,你可以選擇MySQL,也可以用NoSQL。

其WSGI工具箱用Werkzeug(路由模塊),模板引擎則使用Jinja2,這兩個也是Flask框架的核心。

Tornado: Tornado是一種Web服務器軟件的開源版本。Tornado和現在的主流Web服務器框架(包括大多數Python的框架)有着明顯的區別:它是非阻塞式服務器,而且速度相當快。得利於其非阻塞的方式和對epoll的運用,Tornado每秒可以處理數以千計的連接因此Tornado是實時Web服務的一個理想框架

156.Django中哪里用到了線程?哪里用到了協程?哪里用到了進程?

1.Django中耗時的任務用一個進程或者線程來執行,比如發郵件,使用celery.

2.部署django項目是時候,配置文件中設置了進程和協程的相關配置。

157.有用過Django REST framework嗎?

Django REST framework是一個強大而靈活的Web API工具。使用RESTframework的理由有:

Web browsable API對開發者有極大的好處

包括OAuth1a和OAuth2的認證策略

支持ORM和非ORM數據資源的序列化

全程自定義開發--如果不想使用更加強大的功能,可僅僅使用常規的function-based views額外的文檔和強大的社區支持

158.對cookies與session的了解?他們能單獨用嗎?

Session采用的是在服務器端保持狀態的方案,而Cookie采用的是在客戶端保持狀態的方案。但是禁用Cookie就不能得到Session。因為Session是用Session ID來確定當前對話所對應的服務器Session,而Session ID是通過Cookie來傳遞的,禁用Cookie相當於SessionID,也就得不到Session。

爬蟲

159.試列出至少三種目前流行的大型數據庫

160.列舉您使用過的Python網絡爬蟲所用到的網絡數據包?

requests, urllib,urllib2, httplib2

161.爬取數據后使用哪個數據庫存儲數據的,為什么?

162.你用過的爬蟲框架或者模塊有哪些?優缺點?

Python自帶:urllib,urllib2

第三方:requests

框架: Scrapy

urllib 和urllib2模塊都做與請求URL相關的操作,但他們提供不同的功能。

urllib2: urllib2.urlopen可以接受一個Request對象或者url,(在接受Request對象時,並以此可以來設置一個URL的headers),urllib.urlopen只接收一個url。

urllib 有urlencode,urllib2沒有,因此總是urllib, urllib2常會一起使用的原因

scrapy是封裝起來的框架,他包含了下載器,解析器,日志及異常處理,基於多線程,twisted的方式處理,對於固定單個網站的爬取開發,有優勢,但是對於多網站爬取100個網站,並發及分布式處理不夠靈活,不便調整與擴展

requests是一個HTTP庫,它只是用來請求,它是一個強大的庫,下載,解析全部自己處理,靈活性高

Scrapy優點:異步,xpath,強大的統計和log系統,支持不同url。shell方便獨立調試。寫middleware方便過濾。通過管道存入數據庫

163.寫爬蟲是用多進程好?還是多線程好?

164.常見的反爬蟲和應對方法?

165.解析網頁的解析器使用最多的是哪幾個?

166.需要登錄的網頁,如何解決同時限制ip,cookie,session

167.驗證碼的解決?

168.使用最多的數據庫,對他們的理解?

169.編寫過哪些爬蟲中間件?

170.“極驗”滑動驗證碼如何破解?

171.爬蟲多久爬一次,爬下來的數據是怎么存儲?

172.cookie過期的處理問題?

173.動態加載又對及時性要求很高怎么處理?

174.HTTPS有什么優點和缺點?

175.HTTPS是如何實現安全傳輸數據的?

176.TTL,MSL,RTT各是什么?

177.談一談你對Selenium和PhantomJS了解

178.平常怎么使用代理的 ?

179.存放在數據庫(redis、mysql等)。

180.怎么監控爬蟲的狀態?

181.描述下scrapy框架運行的機制?

182.談談你對Scrapy的理解?

183.怎么樣讓 scrapy 框架發送一個 post 請求(具體寫出來)

184.怎么監控爬蟲的狀態 ?

185.怎么判斷網站是否更新?

186.圖片、視頻爬取怎么繞過防盜連接

187.你爬出來的數據量大概有多大?大概多長時間爬一次?

188.用什么數據庫存爬下來的數據?部署是你做的嗎?怎么部署?

189.增量爬取

190.爬取下來的數據如何去重,說一下scrapy的具體的算法依據。

191.Scrapy的優缺點?

192.怎么設置爬取深度?

193.scrapy和scrapy-redis有什么區別?為什么選擇redis數據庫?

194.分布式爬蟲主要解決什么問題?

195.什么是分布式存儲?

196.你所知道的分布式爬蟲方案有哪些?

197.scrapy-redis,有做過其他的分布式爬蟲嗎?

數據庫

MySQL

198.主鍵 超鍵 候選鍵 外鍵

主鍵:數據庫表中對存儲數據對象予以唯一和完整標識的數據列或屬性的組合。一個數據列只能有一個主鍵,且主鍵的取值不能缺失,即不能為空值(Null).

超鍵:在關系中能唯一標識元組的屬性集稱為關系模式的超鍵。一個屬性可以作為一個超鍵,多個屬性組合在一起也可以作為一個超鍵。超鍵包含候選鍵和主鍵。

候選鍵:是最小超鍵,即沒有冗余元素的超鍵。

外鍵:在一個表中存在的另一個表的主鍵稱此表的外鍵。

199.視圖的作用,視圖可以更改么?

視圖是虛擬的表,與包含數據的表不一樣,視圖只包含使用時動態檢索數據的查詢;不包含任何列或數據。使用視圖可以簡化復雜的sql操作,隱藏具體的細節,保護數據;視圖創建后,可以使用與表相同的方式利用它們。

視圖不能被索引,也不能有關聯的觸發器或默認值,如果視圖本身內有order by則對視圖再次order by將被覆蓋。

創建視圖: create view xxx as xxxxxx

對於某些視圖比如未使用聯結子查詢分組聚集函數Distinct Union等,是可以對其更新的,對視圖的更新將對基表進行更新;但是視圖主要用於簡化檢索,保護數據,並不用於更新,而且大部分視圖都不可以更新。

200.drop,delete與truncate的區別

drop直接刪掉表,truncate刪除表中數據,再插入時自增長id又從1開始,delete刪除表中數據,可以加where字句。

1.delete 語句執行刪除的過程是每次從表中刪除一行,並且同時將該行的刪除操作作為事務記錄在日志中保存以便進行回滾操作。truncate table則一次性地從表中刪除所有的數據並不把單獨的刪除操作記錄記入日志保存,刪除行是不能恢復的。並且在刪除的過程中不會激活與表有關的刪除觸發器,執行速度快。

2.表和索引所占空間。當表被truncate后,這個表和索引所占用的空間會恢復到初始大小,而delete操作不會減少表或索引所占用的空間。drop語句將表所占用的空間全釋放掉。

3.一般而言,drop>truncate>delete

4.應用范圍。truncate只能對table,delete可以是table和view

5.truncate和delete只刪除數據,而drop則刪除整個表(結構和數據)

6.truncate與不帶where的delete:只刪除數據,而不刪除表的結構(定義)drop語句將刪除表的結構被依賴的約束(constrain),觸發器(trigger)索引(index);依賴於該表的存儲過程/函數將被保留,但其狀態會變為:invalid.

201.索引的工作原理及其種類

數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢,更新數據庫表中數據。索引的實現通常使用B樹以其變種B+樹。

在數據之外,數據庫系統還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。

為表設置索引要付出代價的:一是增加了數據庫的存儲空間,二是在插入和修改數據時要花費較多的時間(因為索引也要隨之變動)

202.連接的種類

203.數據庫優化的思路

204.存儲過程與觸發器的區別

205.悲觀鎖和樂觀鎖是什么?

206.你常用的mysql引擎有哪些?各引擎間有什么區別?

Redis

207.Redis宕機怎么解決?

宕機:服務器停止服務‘

如果只有一台redis,肯定 會造成數據丟失,無法挽救

多台redis或者是redis集群,宕機則需要分為在主從模式下區分來看:

slave從redis宕機,配置主從復制的時候才配置從的redis,從的會從主的redis中讀取主的redis的操作日志1,在redis中從庫重新啟動后會自動加入到主從架構中,自動完成同步數據;

2, 如果從數據庫實現了持久化,此時千萬不要立馬重啟服務,否則可能會造成數據丟失,正確的操作如下:在slave數據上執行SLAVEOF ON ONE,來斷開主從關系並把slave升級為主庫,此時重新啟動主數據庫,執行SLAVEOF,把它設置為從庫,連接到主的redis上面做主從復制,自動備份數據。

以上過程很容易配置錯誤,可以使用redis提供的哨兵機制來簡化上面的操作。簡單的方法:redis的哨兵(sentinel)的功能

208.redis和mecached的區別,以及使用場景

區別

1、redis和Memcache都是將數據存放在內存中,都是內存數據庫。不過memcache還可以用於緩存其他東西,例如圖片,視頻等等

2、Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲

3、虛擬內存-redis當物流內存用完時,可以將一些很久沒用的value交換到磁盤

4、過期策略-memcache在set時就指定,例如set key1 0 0 8,即永不過期。Redis可以通過例如expire設定,例如expire name 10

5、分布式-設定memcache集群,利用magent做一主多從,redis可以做一主多從。都可以一主一叢

6、存儲數據安全-memcache掛掉后,數據沒了,redis可以定期保存到磁盤(持久化)

7、災難恢復-memcache掛掉后,數據不可恢復,redis數據丟失后可以通過aof恢復

8、Redis支持數據的備份,即master-slave模式的數據備份

9、應用場景不一樣,redis除了作為NoSQL數據庫使用外,還能用做消息隊列,數據堆棧和數據緩存等;Memcache適合於緩存SQL語句,數據集,用戶臨時性數據,延遲查詢數據和session等

使用場景

1,如果有持久方面的需求或對數據類型和處理有要求的應該選擇redis

2,如果簡單的key/value存儲應該選擇memcached.

209.Redis集群方案該怎么做?都有哪些方案?

1,codis

目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在節點數量改變情況下,舊節點數據客恢復到新hash節點

2redis cluster3.0自帶的集群,特點在於他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持節點設置從節點。具體看官方介紹

3.在業務代碼層實現,起幾個毫無關聯的redis實例,在代碼層,對key進行hash計算,然后去對應的redis實例操作數據。這種方式對hash層代碼要求比較高,考慮部分包括,節點失效后的替代算法方案,數據震盪后的字典腳本恢復,實例的監控,等等

210.Redis回收進程是如何工作的

一個客戶端運行了新的命令,添加了新的數據。

redis檢查內存使用情況,如果大於maxmemory的限制,則根據設定好的策略進行回收。

一個新的命令被執行等等,所以我們不斷地穿越內存限制的邊界,通過不斷達到邊界然后不斷回收回到邊界以下。

如果一個命令的結果導致大量內存被使用(例如很大的集合的交集保存到一個新的鍵),不用多久內存限制就會被這個內存使用量超越。

MongoDB

211.MongoDB中對多條記錄做更新操作命令是什么?

212.MongoDB如何才會拓展到多個shard里?

測試

213.編寫測試計划的目的是

214.對關鍵詞觸發模塊進行測試

215.其他常用筆試題目網址匯總

216.測試人員在軟件開發過程中的任務是什么

217.一條軟件Bug記錄都包含了哪些內容?

218.簡述黑盒測試和白盒測試的優缺點

219.請列出你所知道的軟件測試種類,至少5項

220.Alpha測試與Beta測試的區別是什么?

221.舉例說明什么是Bug?一個bug report應包含什么關鍵字?

數據結構

222.數組中出現次數超過一半的數字-Python版

223.求100以內的質數

224.無重復字符的最長子串-Python實現

225.通過2個5/6升得水壺從池塘得到3升水

226.什么是MD5加密,有什么特點?

227.什么是對稱加密和非對稱加密

228.冒泡排序的思想?

229.快速排序的思想?

230.如何判斷單向鏈表中是否有環?

231.你知道哪些排序算法(一般是通過問題考算法)

232.斐波那契數列

**數列定義: **

f 0 = f 1 = 1 f n = f (n-1) + f (n-2)

根據定義

速度很慢,另外(暴棧注意!⚠️️) O(fibonacci n)

def fibonacci(n): if n == 0 or n == 1: return 1 return fibonacci(n - 1) + fibonacci(n - 2)

線性時間的

狀態/循環

def fibonacci(n): a, b = 1, 1 for _ in range(n): a, b = b, a + b return a

遞歸

def fibonacci(n): def fib(n_, s): if n_ == 0: return s[0] a, b = s return fib(n_ - 1, (b, a + b)) return fib(n, (1, 1))

map(zipwith)

def fibs(): yield 1 fibs_ = fibs() yield next(fibs_) fibs__ = fibs() for fib in map(lambad a, b: a + b, fibs_, fibs__): yield fib def fibonacci(n): fibs_ = fibs() for _ in range(n): next(fibs_) return next(fibs)

做緩存

def cache(fn): cached = {} def wrapper(*args): if args not in cached: cached[args] = fn(*args) return cached[args] wrapper.__name__ = fn.__name__ return wrapper @cache def fib(n): if n < 2: return 1 return fib(n-1) + fib(n-2)

利用 funtools.lru_cache 做緩存

from functools import lru_cache @lru_cache(maxsize=32) def fib(n): if n < 2: return 1 return fib(n-1) + fib(n-2)

Logarithmic

矩陣

import numpy as np def fibonacci(n): return (np.matrix([[0, 1], [1, 1]]) ** n)[1, 1]

不是矩陣

def fibonacci(n): def fib(n): if n == 0: return (1, 1) elif n == 1: return (1, 2) a, b = fib(n // 2 - 1) c = a + b if n % 2 == 0: return (a * a + b * b, c * c - a * a) return (c * c - a * a, b * b + c * c) return fib(n)[0]

233.如何翻轉一個單鏈表?

class Node: def __init__(self,data=None,next=None): self.data = data self.next = next def rev(link): pre = link cur = link.next pre.next = None while cur: temp = cur.next cur.next = pre pre = cur cur = tmp return pre if __name__ == '__main__': link = Node(1,Node(2,Node(3,Node(4,Node(5,Node(6,Node7,Node(8.Node(9)))))))) root = rev(link) while root: print(roo.data) root = root.next

234.青蛙跳台階問題

一只青蛙要跳上n層高的台階,一次能跳一級,也可以跳兩級,請問這只青蛙有多少種跳上這個n層台階的方法?

方法1:遞歸

設青蛙跳上n級台階有f(n)種方法,把這n種方法分為兩大類,第一種最后一次跳了一級台階,這類共有f(n-1)種,第二種最后一次跳了兩級台階,這種方法共有f(n-2)種,則得出遞推公式f(n)=f(n-1) + f(n-2),顯然f(1)=1,f(2)=2,這種方法雖然代碼簡單,但效率低,會超出時間上限

class Solution: def climbStairs(self,n): if n ==1: return 1 elif n==2: return 2 else: return self.climbStairs(n-1) + self.climbStairs(n-2)

方法2:用循環來代替遞歸

class Solution: def climbStairs(self,n): if n==1 or n==2: return n a,b,c = 1,2,3 for i in range(3,n+1): c = a+b a = b b = c return c

235.兩數之和 Two Sum

236.搜索旋轉排序數組 Search in Rotated Sorted Array

237.Python實現一個Stack的數據結構

238.寫一個二分查找

239.set 用 in 時間復雜度是多少,為什么?

240.列表中有n個正整數范圍在[0,1000],進行排序;

241.面向對象編程中有組合和繼承的方法實現新的類

大數據

242.找出1G的文件中高頻詞

243.一個大約有一萬行的文本文件統計高頻詞

244.怎么在海量數據中找出重復次數最多的一個?

245.判斷數據是否在大量數據中


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM