網絡編程+併發編程
架構:B/S 和 C/S
B/S:充分發揮PC機的性能
C/S:統一了應用的接口,隸屬於CS架構
OSI模型 七層
我們用五層
應用層http協議 https協議 ftp協議
傳輸層tcp udp 協議(四層交換機)
網絡層IP協議路由器(?)(三次交換機)
數據鏈路層arp協議,交換機 (二層交換機)
物理層網卡,雙絞線 (傳輸電信號)
Arp協議:通過目標ip地址獲取目標mac地址
物理地址:mac地址全球唯一,每個電腦的網卡上
Ip地址:四位點分十進制三十二位點分二進制
交換機的通信方式:
單播:點對點
組播:點對多
廣播:向多個pc端發送數據包
交換機和路由器的區別?
交換機是組織局域網的,經過內部處理解析數據,將數據已點對點,點對多的方式發送給目標
路由器是跨網段的數據傳輸,路由出網絡傳輸的最佳路徑
socket 介於應用層和傳輸層的socket抽象層
Tcp:面向連接的,雙全工的 面向字節流的,安全可靠,會發生黏包,只可以一個客戶端訪問。 三次握手,四次揮手
Udp:無連接的,面向數據報的,不安全,不可靠。可以同時和多個客戶端通信
三次握手:(必須是客戶點先發起)
1.客戶端發起請求鏈接服務端
2.服務端收到請求,向客戶端發送可以連接的請求
3.客服端收到連接,連接成功
四次揮手:(客戶端和服務端都可以發起)
1.客戶端發起斷開連接的請求
2.服務端收到請求,然後準備斷開連接的一些事物
3.服務端發送請求,我已經準備完畢,可以斷開了
4.客戶端收到請求,斷開連接。
為什麼會發生黏包:因為有緩存機制,連續發或者連續收。(在數據傳輸過程中,接收數據端接收數據時不知道該如何接收,造成的數據混亂現象)
合包機制:nagle算法 — 發數據的時候一點一點發,但是接收的時候會一次收到。
拆包機制:發送的數據太大,分開發送,接收的時候,最後不能剛剛接完,就會發生黏包。
都是發生在發送端。
如何解決黏包?
自定義表頭:用struct模塊,事先將要發送文件的大小存下來,發送 過去,然後按著指定數據開始接收。
Struct 模塊 可以將一個整數,封裝為一個指定(一般為4)字節數的數字,這樣接收端就可以指定大小接收這個數字。
操作系統
Dos系統#單用戶單任務
Windows系統#單用戶多任務(早起的Windows)
Unix系統#多用戶多任務
操作系統的作用:1)封裝接口,讓用戶方便使用 2)對系統資源的分配與調度
計算機的五大組成部分:運算器。控制器。存儲器。輸入設備。輸出設備。
編程語言發展史:機器語言,彙編語言,高級語言
並行:(兩件事或者多件事)同一時間點,同時執行 (多個CPU)
併發:(兩件事或者多件事)同一時間間隔,交替執行
阻塞:程序因為類似IO等待、等待時間等導致無法繼續執行
非阻塞:程序遇到類似於IO操作時,不再阻塞等待,如果沒有及時的處理IO,就會報錯或者跳過等待其他操作,
同步:某一個任務的執行必須依賴另一個任務的返回結果
異步:一個任務的執行,不需要依賴另一個任務的返回,只需要告訴另一個任務一聲
進程:cpu資源分配的最小單位 進程由三部分組成:代碼段,數據段,PCB(進程控制塊)
線程:cpu資源調度的最小單位線程由三部分組成:代碼段,數據段,TCB(線程控制塊)
進程的三大基本狀態:
就緒狀態:已經獲得運行所需的所有資源,除CPU
執行狀態:已經獲得所有資源包括CPU,處於正在運行
阻塞狀態:因為各種原因,進程放棄了CPU,導致進程無法繼續執行,此時進程處於內存中,繼續等待獲取CPU的一種狀態。ß
進程學的東西: multiprocessing
1)Process模塊
線程的創建
1)直接創建
p = Process(target = func, argest = (元組形式, 為func所傳的參數)) #實例化進程對象
2)繼承 (Process)
多線程的開啟1)for循環2)多個對象實例化
方法:
start()#開啟進程
join()#感知進程的結束,異步變同步
is_alive()#判斷進程是否存活
terminate()#殺死一個進程
屬性:
name#獲取進程名
pid#獲取進程號
daemon = True #守護進程
守護進程的特點:
#當主進程代碼結束後,守護進程隨主進程結束
#守護進程不能再創建子進程
#守護進程必須在start之前
2)鎖 Lock模塊(互斥鎖/同步鎖)
lock = Lock()#實例化一個鎖對象
lock.acquire()#上鎖
lock.release()#解鎖
RLock模塊(遞歸鎖)
遞歸鎖可以同時acquire多次,但是必須acquire幾次就必須release幾次。都在就會陷入死鎖狀態
死鎖
典型的例子:科學家吃麵 (一個人拿著面,一個人拿著叉子,到最後誰也吃不上面)
信號量Semaphore模塊
sem = Semaphore(int數據類型)#可以指定有多少線程可以同時拿到鎖
sem.acquire()#需要上鎖將這些數據鎖住
sem.release()
事件Event模塊
e = Event()
e.wait()#根據is_set()的狀態來決定,自身的阻塞狀態 如果is_set()為False則為阻塞,如果is_set()為True則為非阻塞
e.is_set()#默認為False,
e.set()#將is_set()的狀態變為True
e.clear()#將is_set()的狀態變為False
典型例子:紅綠燈事件
3)進程間通信(IPC)
Queue模塊#隊列 先進先出 First in first out
q = Queue()#創建隊列對象(可以指定大小)
q.put() #向隊列中添加元素(如果隊列以滿處於阻塞狀態,只有當隊列不滿才可以繼續添加)
q.get()#取出隊列中元素(如果隊列中元素為空處於阻塞狀態,只有對列中有元素才可以繼續取出)
q.full()#判斷一個對列是否 已滿
q.empty()#判斷一個對列是否為空
q.put_nowait() #不阻塞,如果可以繼續往隊列中放數據就繼續放,不能放就報錯
q.get_nowait() #不阻塞,如果有數據就直接獲取,沒有數據就報錯
JoinableQueue()模塊
q = JoinableQueue()
#繼承了Queue模塊,但是新增了兩個方法
q.task_done() #統計對列q有多少個元素被拿走(拿走一個數據就給join返回一個結果),通常與q.get()在一起用 用於生產者
q.join()#感知一個對列的數據被全部執行完畢 與q.put()在一起用 用於消費著
隊列 = 管道 + 鎖
重點:生產者消費著模型
Pipe模塊#管道 (本身是不安全的) (雙全工)
p = Pipe()
conn1, conn2 = Pipe()
管道是不安全的
管道是用於多進程之間通信的一種方式
如果在單進程中使用管道,那麼就是conn1收數據,conn2發數據
如果是conn1發數據,那麼conn2收數據
如果在多進程中使用管道,那麼就必須是父進程中用con1收,子進程中使用conn2發
父進程使用conn1發,子進程中使用conn2收
父進程使用conn2收,子進程中使用conn1發
父進程使用conn2發,子進程中使用conn1收
在管道中有一個著名的錯誤叫做EOFERrror。
是指:父進程中如果關閉了發送端,子進程還繼續接受數據,那麼就會引發EOFError
4)數據共享Manager模塊 Value模塊
men = Manager()
(1)
m.list(列表數據)
m.dict(字典數據)
(2)
with Manager() as m:
……
5)進程池Pool模塊
p = Pool(os.cup_count() +1)#開啟多進程之後,每次處理數據只能指定個數個處理
p.close()
p.join()#close在join之前
方法:
map(func, itreable)#異步處理 itreable ,有返回值,返回值是,每一個func的返回值組成的列表, 自帶close和join
apply(func, argest)#同步處理有返回值,返回值為func的返回值 不需要加close和join
apply_async(func, argest, callback)#異步處理,有返回值,返回一個對象,這個對象有get方法,可以獲取func的返回值
#這個get只能一個一個獲取,以我們一般處理完所有線程後再獲取數據
#func的返回值可以作為參數傳給callback這個回調函數。回調函數在主進程中執行
apply函數中的所有進程都為普通進程
apply_async函數中的所有進程都為守護進程
線程學的東西:threading
GIL:全局解釋器鎖(只有CPython才有)
鎖的是線程:同一時間只允許一個線程訪問CPU #(沒有真正的並行)
1)Thread模塊
線程的創建
1)t = Thresd(target= func. argest = (元組,為func所傳的參數)) 實例化線程對象
2)繼承
多線程的創建
1)for 循環
2)直接實例化多個對象
2)鎖
Lock#互斥鎖(同步鎖)
RLock #遞歸鎖
死鎖#死鎖
信號量Semaphore模塊
sem = Semaphore(int數據類型)#可以指定有多少線程可以同時拿到鎖
sem.acquire()#需要上鎖將這些數據鎖住
sem.release()
事件Event模塊
e = Event()
e.wait()#根據is_set()的狀態來決定,自身的阻塞狀態 如果is_set()為False則為阻塞,如果is_set()為True則為非阻塞
e.is_set()#默認為False,
e.set()#將is_set()的狀態變為True
e.clear()#將is_set()的狀態變為False
3)條件Condition模塊
條件是讓程序員自行去調度線程的一個機制
方法:
acquire()
release()
wait() #讓線程阻塞住
notify(int數據類型)#是指給wait發一個信號,讓wait變成不阻塞#int數據類型,是指你要給多少wai發信號
4)定時器Timer模塊
創建:Timer(time, func)
#time:睡眠時間,以秒為單位
#func:睡眠之後,需要執行的任務
5)線程池
進程與線程的區別:
進程資源分配的基本單位,線程是cpu調度的基本單位。
線程不可以自己獨立擁有資源。線程的執行,必須依賴於所屬進程中的資源。
進程中必須至少應該有一個線程。
線程和進程的比較:
1)cpu切換進程比切換線程慢很多,在python中如果IO操作過多的話,使用線程最好
2)在同一個進程內,所有線程共享這個進程pid,也就是說所有線程共享所屬進程的所有資源和內存地址
3)在同一個進程內,所有線程共享該進程中的全局變量
4)因為GIL鎖的存在,在CPython中,沒有真正的線程並行。但是有真正的多進程並行
當你的任務是計算密集的情況下,使用多進程好。
總結:在CPython中,IO密集用多線程,計算密集用多線程。
5)關於守護線程和守護進程的事情:(注意:代碼執行結束,並不代表程序結束)
守護進程:要麼自己正常結束,要麼根據父進程的代碼執行結束而結束
守護線程:要麼自己正常結束,要麼根據父線程的執行結束而結束(會等其餘子線程運行結束)
閱讀更多 程序猿Monster 的文章