函數須要手動傳參self、cls,方法自動傳,好比對象方法自動傳self,類方法自動傳cls,而函數相對而言須要手動傳,好比靜態綁定的函數,self是須要手動傳值得,好比咱們日常使用的函數都是手動傳值。html
判斷函數和方法的方式前端
使用types模塊中的FunctionType和MethodType進行判斷mysql
偏函數的做用在於:當函數的參數個數太多,須要簡化時,使用 functools.partial 能夠建立一個新的函數,這個新函數能夠固定住原函數的部分參數,從而在調用時更簡單。web
也就是說,當咱們須要使用一個函數f1,該函數須要傳多個參數時候,能夠先試用functools.partial建立一個偏函數f2,該函數f2能夠先傳一個參數a進去,而後再使用f2傳入其它參數b、c執行,效果等同於f1(a, b, c)執行同樣。ajax
示例:redis
int()函數能夠把字符串轉換爲整數,當僅傳入字符串時,int()函數默認按十進制轉換:算法
print(int("333666")) # 333666
但int()函數還提供額外的base參數,默認值爲10。若是傳入base參數,就能夠作N進制的轉換:sql
print(int("333666", base=8)) # 112566 print(int("333666", base=16)) # 3356262
假設要轉換大量的二進制字符串,每次都傳入int(x, base=2)很是麻煩,因而,咱們想到,能夠定義一個new_int()的函數,默認把base=2傳進去:數據庫
def new_int(x, base=2): return int(x, base) print(new_int("1000000")) # 64 print(new_int("10011100")) # 156
functools.partial就是幫助咱們建立一個偏函數,不須要咱們本身定義new_int(),能夠直接使用下面的代碼建立一個新的函數new_int:後端
from functools import partial new_int = partial(int, base=2) print(new_int("10000000")) # 128
因此,functiools.partial的做用就是把一個函數的某些參數固定住(設爲一個默認參數),返回一個新的函數,調用這個函數會更方便些。
tips:建立偏函數時,實際上能夠接受函數對象,*args,**kwargs這三個參數
from functools import partial new_min = partial(min, 10) print(new_min(20, 12, 16)) # 10 # 至關於 args = (10, 20, 12, 16) min(*args)
短輪詢的基本思路就是瀏覽器每隔一段時間向瀏覽器發送http請求,服務器端在收到請求後,不管是否有數據更新,都直接進行響應。這種方式實現的即時通訊,本質上仍是瀏覽器發送請求,服務器接受請求的一個過程,經過讓客戶端不斷的進行請求,使得客戶端可以模擬實時地收到服務器端的數據的變化。
這種方式的優勢是比較簡單,易於理解,實現起來也沒有什麼技術難點。缺點是顯而易見的,這種方式因爲須要不斷的創建http鏈接,嚴重浪費了服務器端和客戶端的資源。尤爲是在客戶端,距離來講,若是有數量級想對比較大的人同時位於基於短輪詢的應用中,那麼每個用戶的客戶端都會瘋狂的向服務器端發送http請求,並且不會間斷。人數越多,服務器端壓力越大,這是很不合理的。
所以短輪詢不適用於那些同時在線用戶數量比較大,而且很注重性能的Web應用。
var xhr = new XMLHttpRequest();
setInterval(function(){
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
};
xhr.send();
},1000)
ajax實現:
當服務器收到客戶端發來的請求後,服務器端不會直接進行響應,而是先將這個請求掛起,而後判斷服務器端數據是否有更新。若是有更新,則進行響應,若是一直沒有數據,則到達必定的時間限制(服務器端設置)才返回。 。 客戶端JavaScript響應處理函數會在處理完服務器返回的信息後,再次發出請求,從新創建鏈接。
長輪詢和短輪詢比起來,明顯減小了不少沒必要要的http請求次數,相比之下節約了資源。長輪詢的缺點在於,鏈接掛起也會致使資源的浪費。
function ajax(){
var xhr = new XMLHttpRequest();
xhr.open('GET','/user');
xhr.onreadystatechange = function(){
ajax();
};
xhr.send();
}
輪詢與長輪詢都是基於HTTP的,二者自己存在着缺陷:輪詢須要更快的處理速度;長輪詢則更要求處理併發的能力;二者都是「被動型服務器」的體現:服務器不會主動推送信息,而是在客戶端發送ajax請求後進行返回的響應。而理想的模型是"在服務器端數據有了變化後,能夠主動推送給客戶端",這種"主動型"服務器是解決這類問題的很好的方案。Web Sockets就是這樣的方案。
1. HTTP協議與TCP/IP協議的關係
HTTP的長鏈接和短鏈接本質上是TCP長鏈接和短鏈接。HTTP屬於應用層協議,在傳輸層使用TCP協議,在網絡層使用IP協議。IP協議主要解決網絡路由和尋址問題,TCP協議主要解決如何在IP層之上可靠的傳遞數據包,使在網絡上的另外一端收到發端發出的全部包,而且順序與發出順序一致。TCP有可靠,面向鏈接的特色。
TCP/IP是個協議組,可分爲三個層次:網絡層、傳輸層和應用層。
在網絡層有IP協議、ICMP協議、ARP協議、RARP協議和BOOTP協議。
在傳輸層中有TCP協議與UDP協議。
在應用層有:TCP包括FTP、HTTP、TELNET、SMTP等協議
UDP包括DNS、TFTP等協議
更細緻地瞭解,能夠參考這篇文章:細說OSI七層協議模型及OSI參考模型中的數據封裝過程
2. 如何理解HTTP協議是無狀態的
HTTP協議是無狀態的,指的是協議對於事務處理沒有記憶能力,服務器不知道客戶端是什麼狀態。也就是說,打開一個服務器上的網頁和你以前打開這個服務器上的網頁之間沒有任何聯繫。HTTP是一個無狀態的面向鏈接的協議,無狀態不表明HTTP不能保持TCP鏈接,更不能表明HTTP使用的是UDP協議(無鏈接)。
3. 什麼是長鏈接、短鏈接?
在HTTP/1.0中,默認使用的是短鏈接。也就是說,瀏覽器和服務器每進行一次HTTP操做,就創建一次鏈接,但任務結束就中斷鏈接。若是客戶端瀏覽器訪問的某個HTML或其餘類型的 Web頁中包含有其餘的Web資源,如JavaScript文件、圖像文件、CSS文件等;當瀏覽器每遇到這樣一個Web資源,就會創建一個HTTP會話。
短鏈接:
鏈接->傳輸數據->關閉鏈接
HTTP是無狀態的,瀏覽器和服務器每進行一次HTTP操做,就創建一次鏈接,但任務結束就中斷鏈接。
也能夠這樣說:短鏈接是指SOCKET鏈接後發送後接收完數據後立刻斷開鏈接。
但從 HTTP/1.1起,默認使用長鏈接,用以保持鏈接特性。使用長鏈接的HTTP協議,會在響應頭有加入這行代碼:
Connection:keep-alive
在使用長鏈接的狀況下,當一個網頁打開完成後,客戶端和服務器之間用於傳輸HTTP數據的 TCP鏈接不會關閉,若是客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經創建的鏈接。Keep-Alive不會永久保持鏈接,它有一個保持時間,能夠在不一樣的服務器軟件(如Apache)中設定這個時間。實現長鏈接要客戶端和服務端都支持長鏈接。
長鏈接
鏈接->傳輸數據->保持鏈接 -> 傳輸數據-> 。。。 ->關閉鏈接。
長鏈接指創建SOCKET鏈接後無論是否使用都保持鏈接,但安全性較差。
HTTP協議的長鏈接和短鏈接,實質上是TCP協議的長鏈接和短鏈接。
3.1 TCP鏈接
當網絡通訊時採用TCP協議時,在真正的讀寫操做以前,server與client之間必須創建一個鏈接,當讀寫操做完成後,雙方再也不須要這個鏈接 時它們能夠釋放這個鏈接,鏈接的創建是須要三次握手的,而釋放則須要4次握手,因此說每一個鏈接的創建都是須要資源消耗和時間消耗的
經典的三次握手創建雙向鏈接圖:
經典的四次揮手斷開鏈接圖:
TCP的握手揮手過程,具體推薦參看黃日成的:從 TCP 三次握手提及:淺析TCP協議中的疑難雜症
3.2 TCP短鏈接
咱們模擬一下TCP短鏈接的狀況,client向server發起鏈接請求,server接到請求,而後雙方創建鏈接。client向server 發送消息,server迴應client,而後一次讀寫就完成了,這時候雙方任何一個均可以發起close操做,不過通常都是client先發起 close操做。爲何呢,通常的server不會回覆完client後當即關閉鏈接的,固然不排除有特殊的狀況。從上面的描述看,短鏈接通常只會在 client/server間傳遞一次讀寫操做
短鏈接的優勢是:管理起來比較簡單,存在的鏈接都是有用的鏈接,不須要額外的控制手段
3.3 TCP長鏈接
接下來咱們再模擬一下長鏈接的狀況,client向server發起鏈接,server接受client鏈接,雙方創建鏈接。Client與server完成一次讀寫以後,它們之間的鏈接並不會主動關閉,後續的讀寫操做會繼續使用這個鏈接。
首先說一下TCP/IP詳解上講到的TCP保活功能,保活功能主要爲服務器應用提供,服務器應用但願知道客戶主機是否崩潰,從而能夠表明客戶使用資源。若是客戶已經消失,使得服務器上保留一個半開放的鏈接,而服務器又在等待來自客戶端的數據,則服務器將應遠等待客戶端的數據,保活功能就是試圖在服務 器端檢測到這種半開放的鏈接。
若是一個給定的鏈接在兩小時內沒有任何的動做,則服務器就向客戶發一個探測報文段,客戶主機必須處於如下4個狀態之一:
①客戶主機依然正常運行,並從服務器可達。客戶的TCP響應正常,而服務器也知道對方是正常的,服務器在兩小時後將保活定時器復位。
②客戶主機已經崩潰,而且關閉或者正在從新啓動。在任何一種狀況下,客戶的TCP都沒有響應。服務端將不能收到對探測的響應,並在75秒後超時。服務器總共發送10個這樣的探測 ,每一個間隔75秒。若是服務器沒有收到一個響應,它就認爲客戶主機已經關閉並終止鏈接。
③客戶主機崩潰並已經從新啓動。服務器將收到一個對其保活探測的響應,這個響應是一個復位,使得服務器終止這個鏈接。
④客戶機正常運行,可是服務器不可達,這種狀況與2相似,TCP能發現的就是沒有收到探查的響應。
3.4 長鏈接短鏈接操做過程
短鏈接的操做步驟是:
創建鏈接——數據傳輸——關閉鏈接...創建鏈接——數據傳輸——關閉鏈接
長鏈接的操做步驟是:
創建鏈接——數據傳輸...(保持鏈接)...數據傳輸——關閉鏈接
4. 長鏈接和短鏈接的優勢和缺點
由上能夠看出,長鏈接能夠省去較多的TCP創建和關閉的操做,減小浪費,節約時間。對於頻繁請求資源的客戶來講,較適用長鏈接。不過這裏存在一個問題,存活功能的探測週期太長,還有就是它只是探測TCP鏈接的存活,屬於比較斯文的作法,遇到惡意的鏈接時,保活功能就不夠使了。在長鏈接的應用場景下,client端通常不會主動關閉它們之間的鏈接,Client與server之間的鏈接若是一直不關閉的話,會存在一個問題,隨着客戶端鏈接愈來愈多,server遲早有扛不住的時候,這時候server端須要採起一些策略,如關閉一些長時間沒有讀寫事件發生的鏈接,這樣可 以免一些惡意鏈接致使server端服務受損;若是條件再容許就能夠以客戶端機器爲顆粒度,限制每一個客戶端的最大長鏈接數,這樣能夠徹底避免某個蛋疼的客戶端連累後端服務。
短鏈接對於服務器來講管理較爲簡單,存在的鏈接都是有用的鏈接,不須要額外的控制手段。但若是客戶請求頻繁,將在TCP的創建和關閉操做上浪費時間和帶寬。
長鏈接和短鏈接的產生在於client和server採起的關閉策略,具體的應用場景採用具體的策略,沒有十全十美的選擇,只有合適的選擇。
5. 何時用長鏈接,短鏈接?
長鏈接多用於操做頻繁,點對點的通信,並且鏈接數不能太多狀況,。每一個TCP鏈接都須要三步握手,這須要時間,若是每一個操做都是先鏈接,再操做的話那麼處理速度會下降不少,因此每一個操做完後都不斷開,次處理時直接發送數據包就OK了,不用創建TCP鏈接。例如:數據庫的鏈接用長鏈接, 若是用短鏈接頻繁的通訊會形成socket錯誤,並且頻繁的socket 建立也是對資源的浪費。
而像WEB網站的http服務通常都用短連接,由於長鏈接對於服務端來講會耗費必定的資源,而像WEB網站這麼頻繁的成千上萬甚至上億客戶端的鏈接用短鏈接會更省一些資源,若是用長鏈接,並且同時有成千上萬的用戶,若是每一個用戶都佔用一個鏈接的話,那可想而知吧。因此併發量大,但每一個用戶無需頻繁操做狀況下需用短連好。
WebSocket是Html5定義的一個新協議,與傳統的http協議不一樣,該協議能夠實現服務器與客戶端之間全雙工通訊。簡單來講,首先須要在客戶端和服務器端創建起一個鏈接,這部分須要http。鏈接一旦創建,客戶端和服務器端就處於平等的地位,能夠相互發送數據,不存在請求和響應的區別。
WebSocket的優勢是實現了雙向通訊,缺點是服務器端的邏輯很是複雜。如今針對不一樣的後臺語言有不一樣的插件可使用。
具體能夠看看這篇文章:WebSocket請求過程分析及web聊天室
短期內大量用戶對同一服務器發送請求,致使瞬間流量巨大,也就是高併發劇增,這種流量出現峯值的現象,因爲服務器的處理資源能力的有限的,因此峯值出現的時候,很容易致使服務器宕機,用戶沒法訪問的狀況出現。
具體實例有不少:好比每一年的春運買票同一時間大佬用戶去搶購車票,好比淘寶雙十一搶購活動,又好比秒殺活動,都是在短期內用戶發起請求致使流量劇增,服務器頂不住就會宕機。
解決的辦法之一就是流量削峯方案:
削峯方案本質上就是更多的延緩用戶請求,以及層層過濾用戶的訪問需求,遵循「最後落地到數據庫的請求數要儘可能少」的原則,來變相減輕服務器的壓力。
總結:
1.對於秒殺這樣的高併發場景業務,最基本的原則就是將請求攔截在系統上游,下降下游壓力。若是不在前端攔截極可能形成數據庫(mysql、oracle等)讀寫鎖衝突,甚至致使死鎖,最終還有可能出現雪崩等場景。
2.劃分好動靜資源,靜態資源使用CDN進行服務分發。
3.充分利用緩存(redis等):增長QPS,從而加大整個集羣的吞吐量。
4.高峯值流量是壓垮系統很重要的緣由,因此須要Kafka等消息隊列在一端承接瞬時的流量洪峯,在另外一端平滑地將消息推送出去。
悲觀鎖
老是假設最壞的狀況,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用,其它線程阻塞,用完後再把資源轉讓給其它線程)。傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖。
悲觀鎖使用場景
比較適合寫入操做比較頻繁的場景,若是出現大量的讀取操做,每次讀取的時候都會進行加鎖,這樣會增長大量的鎖的開銷,下降了系統的吞吐量。
樂觀鎖
老是假設最好的狀況,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可使用版本號機制和CAS算法實現。樂觀鎖適用於多讀的應用類型,這樣能夠提升吞吐量,像數據庫提供的相似於write_condition機制,其實都是提供的樂觀鎖。
樂觀鎖使用場景
比較適合讀取操做比較頻繁的場景,若是出現大量的寫入操做,數據發生衝突的可能性就會增大,爲了保證數據的一致性,應用層須要不斷的從新獲取數據,這樣會增長大量的查詢操做,下降了系統的吞吐量。