每日測(cè)驗(yàn)
-
簡(jiǎn)述死鎖現(xiàn)象
-
你用過(guò)哪些隊(duì)列
-
闡述進(jìn)程池線程池概念及基本使用
-
什么是協(xié)程,如何簡(jiǎn)單實(shí)現(xiàn)
昨日內(nèi)容回顧
-
死鎖現(xiàn)象
""" 即便你知道如何搶鎖釋放鎖 也極有可能造成程序的死鎖現(xiàn)象 后續(xù)我們?cè)趯戫?xiàng)目的時(shí)候 也不會(huì)自己去處理鎖的問(wèn)題 都是底層封裝好的 所以你不用擔(dān)心 """
-
遞歸鎖
""" 它也是一把互斥鎖昌粤,但是它可以被第一個(gè)搶到它的人連續(xù)的acquire和release 每acquire一次內(nèi)部有一個(gè)引用計(jì)數(shù)加1 每release一次內(nèi)部有一個(gè)引用計(jì)數(shù)減1 只要引用計(jì)數(shù)不為0 永遠(yuǎn)也無(wú)法被其他人搶到 """
-
信號(hào)量
""" 信號(hào)量在不同的領(lǐng)域和知識(shí)階段可能對(duì)應(yīng)不同的概念 如果將互斥鎖比喻成一個(gè)廁所 那么信號(hào)量就相當(dāng)于多個(gè)廁所 """
-
event事件
""" 一些線程/進(jìn)程等待另外一些線程/進(jìn)程發(fā)送可以運(yùn)行的信號(hào) 才開(kāi)始運(yùn)行 from threading import Event e = Event() # 等待 e.wait() # 發(fā)送信號(hào) e.set() """
-
各種隊(duì)列
""" 1 常見(jiàn)隊(duì)列 queue 先進(jìn)先出 q = queue.Queue() q.put() q.get(timeout=3) q.get_nowait() q.full() q.empty() 2 后進(jìn)先出 LifoQueue() q = queue.LifoQueue() q.put() q.get() 3 優(yōu)先級(jí) PriorityQueue() q = queue.PriorityQueue() q.put((10,'data')) q.put((-5,'data')) 元祖里面的第一個(gè)參數(shù)是數(shù)字 并且支持負(fù)數(shù) 數(shù)字越小優(yōu)先級(jí)越高 """
-
進(jìn)程池線程池
""" 硬件的發(fā)展肯定是趕不上軟件的開(kāi)發(fā)速度的 思考我們以前借助于開(kāi)設(shè)進(jìn)程和線程的方式來(lái)實(shí)現(xiàn)TCP服務(wù)端的并發(fā) 每來(lái)一個(gè)客戶端就開(kāi)設(shè)一個(gè)進(jìn)程或者線程 無(wú)論是開(kāi)設(shè)進(jìn)程還是開(kāi)設(shè)線程其實(shí)都需要消耗一定的資源 我們應(yīng)該在保證計(jì)算機(jī)硬件安全的情況下页滚,最大限度的利用計(jì)算機(jī) 池的概念 它的出現(xiàn)是為了保證計(jì)算機(jī)硬件的安全 降低了程序的運(yùn)行效率 但是保證了計(jì)算機(jī)硬件安全 """ # 進(jìn)程池線程池都不需要我們自己去造 直接使用封裝好的模塊 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor # 1 生成進(jìn)程池線程池 pool1 = ThreadPoolExecutor() # 不填默認(rèn)是cpu個(gè)數(shù)的五倍 pool2 = ProcessPoolExecutor() # 不填默認(rèn)就是cpu的個(gè)數(shù) # 2 朝池子中提交任務(wù) pool1.submit(task,args...) # 異步提交 # 3 submit其實(shí)會(huì)返回一個(gè)Future類的對(duì)象 該對(duì)象調(diào)用result就能獲取到任務(wù)的結(jié)果 res = pool1.submit(task,args...) res.result() # 同步 # 4 池子對(duì)象的方法 pool1.shotdown() # 關(guān)閉池子 等待池子中所有的任務(wù)運(yùn)行結(jié)束 再繼續(xù)往后執(zhí)行代碼 # 5 異步回調(diào)機(jī)制 """給每一個(gè)異步提交的任務(wù)綁定一個(gè)方法萤彩,一旦任務(wù)有結(jié)果了會(huì)立刻自動(dòng)觸發(fā)該方法""" pool1.submit(task,args).add_done_callback(call_back) # 注意異步回調(diào)函數(shù)拿到的也是一個(gè)對(duì)象
-
協(xié)程
""" 單線程下實(shí)現(xiàn)并發(fā) 這個(gè)概念完全是我們程序員自己想出來(lái) 多道技術(shù) 切換+保存狀態(tài) 我們想通過(guò)代碼層面自己檢測(cè)IO行為村视。一旦遇到IO代碼層面實(shí)現(xiàn)切換 這樣給操作系統(tǒng)的感覺(jué)好像我這個(gè)程序一直運(yùn)行沒(méi)有IO 欺騙操作系統(tǒng)從而最大化的利用CPU 一味的切換加保存狀態(tài)也有可能會(huì)降低程序的效率 計(jì)算密集型的 不行 IO密集型的 可以 """
-
gevent模塊
# 該模塊能夠幫我們檢測(cè)IO并實(shí)現(xiàn)切換 from gevent import monkey;monkey.patch_all() from gevent import spawn # spawn在檢測(cè)的時(shí)候 是異步提交的 spawn(server).join() g = spawn(server) g.join
-
基于協(xié)程實(shí)現(xiàn)TCP服務(wù)端單線程下的并發(fā)
# 代碼稍微摟一眼 感受它的牛逼之處
總結(jié)
"""
多進(jìn)程下面開(kāi)設(shè)多線程
多線程下面再利用協(xié)程
最大長(zhǎng)度的提升軟件運(yùn)行的效率
"""
今日內(nèi)容概要
-
IO模型
-
復(fù)習(xí)網(wǎng)絡(luò)和并發(fā)知識(shí)點(diǎn)
-
后期課程安排
IO模型簡(jiǎn)介
"""
我們這里研究的IO模型都是針對(duì)網(wǎng)絡(luò)IO的
Stevens在文章中一共比較了五種IO Model:
* blocking IO 阻塞IO
* nonblocking IO 非阻塞IO
* IO multiplexing IO多路復(fù)用
* signal driven IO 信號(hào)驅(qū)動(dòng)IO
* asynchronous IO 異步IO
由signal driven IO(信號(hào)驅(qū)動(dòng)IO)在實(shí)際中并不常用伊磺,所以主要介紹其余四種IO Model盛正。
"""
#1)等待數(shù)據(jù)準(zhǔn)備 (Waiting for the data to be ready)
#2)將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程中(Copying the data from the kernel to the process)
同步異步
阻塞非阻塞
常見(jiàn)的網(wǎng)絡(luò)阻塞狀態(tài):
accept
recv
recvfrom
send雖然它也有io行為 但是不在我們的考慮范圍
阻塞IO模型
"""
我們之前寫的都是阻塞IO模型 協(xié)程除外
"""
import socket
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn, addr = server.accept()
while True:
try:
data = conn.recv(1024)
if len(data) == 0:break
print(data)
conn.send(data.upper())
except ConnectionResetError as e:
break
conn.close()
# 在服務(wù)端開(kāi)設(shè)多進(jìn)程或者多線程 進(jìn)程池線程池 其實(shí)還是沒(méi)有解決IO問(wèn)題
該等的地方還是得等 沒(méi)有規(guī)避
只不過(guò)多個(gè)人等待的彼此互不干擾
非阻塞IO
"""
要自己實(shí)現(xiàn)一個(gè)非阻塞IO模型
"""
import socket
import time
server = socket.socket()
server.bind(('127.0.0.1', 8081))
server.listen(5)
server.setblocking(False)
# 將所有的網(wǎng)絡(luò)阻塞變?yōu)榉亲枞?r_list = []
del_list = []
while True:
try:
conn, addr = server.accept()
r_list.append(conn)
except BlockingIOError:
# time.sleep(0.1)
# print('列表的長(zhǎng)度:',len(r_list))
# print('做其他事')
for conn in r_list:
try:
data = conn.recv(1024) # 沒(méi)有消息 報(bào)錯(cuò)
if len(data) == 0: # 客戶端斷開(kāi)鏈接
conn.close() # 關(guān)閉conn
# 將無(wú)用的conn從r_list刪除
del_list.append(conn)
continue
conn.send(data.upper())
except BlockingIOError:
continue
except ConnectionResetError:
conn.close()
del_list.append(conn)
# 揮手無(wú)用的鏈接
for conn in del_list:
r_list.remove(conn)
del_list.clear()
# 客戶端
import socket
client = socket.socket()
client.connect(('127.0.0.1',8081))
while True:
client.send(b'hello world')
data = client.recv(1024)
print(data)
總結(jié)
"""
雖然非阻塞IO給你的感覺(jué)非常的牛逼
但是該模型會(huì) 長(zhǎng)時(shí)間占用著CPU并且不干活 讓CPU不停的空轉(zhuǎn)
我們實(shí)際應(yīng)用中也不會(huì)考慮使用非阻塞IO模型
任何的技術(shù)點(diǎn)都有它存在的意義
實(shí)際應(yīng)用或者是思想借鑒
"""
IO多路復(fù)用
"""
當(dāng)監(jiān)管的對(duì)象只有一個(gè)的時(shí)候 其實(shí)IO多路復(fù)用連阻塞IO都比比不上!P悸瘛豪筝!
但是IO多路復(fù)用可以一次性監(jiān)管很多個(gè)對(duì)象
server = socket.socket()
conn,addr = server.accept()
監(jiān)管機(jī)制是操作系統(tǒng)本身就有的 如果你想要用該監(jiān)管機(jī)制(select)
需要你導(dǎo)入對(duì)應(yīng)的select模塊
"""
import socket
import select
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False)
read_list = [server]
while True:
r_list, w_list, x_list = select.select(read_list, [], [])
"""
幫你監(jiān)管
一旦有人來(lái)了 立刻給你返回對(duì)應(yīng)的監(jiān)管對(duì)象
"""
# print(res) # ([<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080)>], [], [])
# print(server)
# print(r_list)
for i in r_list: #
"""針對(duì)不同的對(duì)象做不同的處理"""
if i is server:
conn, addr = i.accept()
# 也應(yīng)該添加到監(jiān)管的隊(duì)列中
read_list.append(conn)
else:
res = i.recv(1024)
if len(res) == 0:
i.close()
# 將無(wú)效的監(jiān)管對(duì)象 移除
read_list.remove(i)
continue
print(res)
i.send(b'heiheiheiheihei')
# 客戶端
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
client.send(b'hello world')
data = client.recv(1024)
print(data)
總結(jié)
"""
監(jiān)管機(jī)制其實(shí)有很多
select機(jī)制 windows linux都有
poll機(jī)制 只在linux有 poll和select都可以監(jiān)管多個(gè)對(duì)象 但是poll監(jiān)管的數(shù)量更多
上述select和poll機(jī)制其實(shí)都不是很完美 當(dāng)監(jiān)管的對(duì)象特別多的時(shí)候
可能會(huì)出現(xiàn) 極其大的延時(shí)響應(yīng)
epoll機(jī)制 只在linux有
它給每一個(gè)監(jiān)管對(duì)象都綁定一個(gè)回調(diào)機(jī)制
一旦有響應(yīng) 回調(diào)機(jī)制立刻發(fā)起提醒
針對(duì)不同的操作系統(tǒng)還需要考慮不同檢測(cè)機(jī)制 書寫代碼太多繁瑣
有一個(gè)人能夠根據(jù)你跑的平臺(tái)的不同自動(dòng)幫你選擇對(duì)應(yīng)的監(jiān)管機(jī)制
selectors模塊
"""
異步IO
"""
異步IO模型是所有模型中效率最高的 也是使用最廣泛的
相關(guān)的模塊和框架
模塊:asyncio模塊
異步框架:sanic tronado twisted
速度快!H副恕壤蚜!
"""
import threading
import asyncio
@asyncio.coroutine
def hello():
print('hello world %s'%threading.current_thread())
yield from asyncio.sleep(1) # 換成真正的IO操作
print('hello world %s' % threading.current_thread())
loop = asyncio.get_event_loop()
tasks = [hello(),hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
四個(gè)IO模型對(duì)比
參考博客園圖解即寡,稍微了解即可
網(wǎng)絡(luò)并發(fā)知識(shí)點(diǎn)梳理
軟件開(kāi)發(fā)架構(gòu)
-
互聯(lián)網(wǎng)協(xié)議
""" osi七層 五層 每一層都是干嘛的 以太網(wǎng)協(xié)議 廣播風(fēng)暴 IP協(xié)議 TCP/UDP """
三次握手四次揮手
socket簡(jiǎn)介
TCP黏包問(wèn)題 定制固定長(zhǎng)度的報(bào)頭
UDP協(xié)議
socketserver模塊
- 操作系統(tǒng)發(fā)展史
- 多道技術(shù)
- 進(jìn)程理論
- 開(kāi)啟進(jìn)程的兩種方式
- 互斥鎖
- 生產(chǎn)者消費(fèi)者模型
- 線程理論
- 開(kāi)啟線程的兩種方式
- GIL全局解釋器鎖
- 進(jìn)程池線程池
- 協(xié)程的概念
- IO模型的了解