1. 程式人生 > 實用技巧 >python 面試題(進階)

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.判斷資料是否在大量資料中