?
創(chuàng)新互聯(lián)建站專(zhuān)注于懷寧網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供懷寧營(yíng)銷(xiāo)型網(wǎng)站建設(shè),懷寧網(wǎng)站制作、懷寧網(wǎng)頁(yè)設(shè)計(jì)、懷寧網(wǎng)站官網(wǎng)定制、重慶小程序開(kāi)發(fā)公司服務(wù),打造懷寧網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供懷寧網(wǎng)站排名全網(wǎng)營(yíng)銷(xiāo)落地服務(wù)。
目錄
異步編程:...1
同步、異步:...1
阻塞、非阻塞:...2
同步、異步與阻塞、非阻塞區(qū)別:...2
聯(lián)系:...2
IO模型...2
py中的IO ?multiplexing——selectors:...5
?
?
?
?
你做完了,我才能做,同步,串行;我讓你打飯,你不打好給我,我不走開(kāi),直到你打飯給了我;
你做你的,我做我的,異步,步調(diào)不一致;我讓你打飯,你正打著,我不等你,但我會(huì)盯著你,你打完我過(guò)來(lái)拿走,異步并不保證多長(zhǎng)時(shí)間打完飯;
?
函數(shù)或方法調(diào)用的時(shí)候,被調(diào)用者是否得到最終結(jié)果;
直接得到最終結(jié)果的,就是同步調(diào)用;
不直接得到最終結(jié)果的,就是異步調(diào)用;
某一方法是否在這個(gè)方法調(diào)用完時(shí),是否能獲得最終結(jié)果;
?
同步、異步區(qū)別:
同步,一直要執(zhí)行到返回結(jié)果;
異步,直接返回了,但不是最終結(jié)果,調(diào)用者不能通過(guò)這種調(diào)用得到結(jié)果,還要通過(guò)被調(diào)用者,使用其它方式通知調(diào)用者,來(lái)取回最終結(jié)果;
?
?
函數(shù)或方法調(diào)用時(shí),是否立刻返回;
不立即返回,就是阻塞調(diào)用;
立即返回,就是非阻塞調(diào)用;
time.sleep()和event.wait(),event.wait()要優(yōu)于time.sleep(),wait會(huì)主動(dòng)讓出時(shí)間片,其它線程可以被調(diào)度,而sleep會(huì)占用時(shí)間片不讓出;
?
?
它們不相關(guān);
同步、異步,強(qiáng)調(diào)的是結(jié)果;
阻塞、非阻塞強(qiáng)調(diào)的是時(shí)間,是否等待;
?
?
注:調(diào)用者、被調(diào)用者;
同步阻塞,我啥事不干,就等你打飯給我,打飯是結(jié)果,而且我啥事不干一直等;
同步非阻塞,我等著你打飯給我,但我可以玩手機(jī)、看電視,打飯是結(jié)果,但我不一直等;
異步阻塞,我要打飯,你說(shuō)等叫號(hào),并沒(méi)有返回飯給我,我啥事不干,就等著飯好了你叫我,叫號(hào);
異步非阻塞,我要打飯,你說(shuō)等叫號(hào),并沒(méi)有返回飯給我,我在旁邊玩手機(jī)、看電視,飯打好了你叫我;
?
?
同步IO、異步IO、IO多路復(fù)用:
IO過(guò)程分2階段:
數(shù)據(jù)準(zhǔn)備階段,內(nèi)核從輸入設(shè)備讀寫(xiě)數(shù)據(jù)(淘米、放鍋里煮);
內(nèi)核空間復(fù)制回用戶(hù)進(jìn)程緩沖區(qū)階段,進(jìn)程從內(nèi)核復(fù)制數(shù)據(jù)(盛飯,從內(nèi)核這個(gè)飯鍋里把飯裝到碗里來(lái));
?
注:
sendfile,disk緩沖區(qū)-->內(nèi)核緩沖區(qū)(網(wǎng)絡(luò)緩沖區(qū))-->發(fā)出;
0拷貝,網(wǎng)絡(luò)緩沖區(qū)上有disk緩沖區(qū)的快捷方式,直接從disk緩沖區(qū)發(fā)出;
?
sync同步IO模型:
阻塞IO、非阻塞IO、IO多路復(fù)用;
?
阻塞IO,sync blocking IO:
進(jìn)程等待(阻塞),直到讀寫(xiě)完成,全程等待;
?
非阻塞IO,sync non-blocking IO:
進(jìn)程調(diào)用read操作,如果IO設(shè)備沒(méi)有準(zhǔn)備好,立即返回ERROR,進(jìn)程不阻塞,用戶(hù)可以再次發(fā)起系統(tǒng)調(diào)用,如果內(nèi)核已準(zhǔn)備好,就阻塞,然后復(fù)制數(shù)據(jù)到用戶(hù)空間;
第1階段數(shù)據(jù)沒(méi)有準(zhǔn)備好,就先忙別的,等會(huì)再來(lái)看看,檢查數(shù)據(jù)是否準(zhǔn)備好了的過(guò)程是非阻塞;systemcall后返回的是異常,直到return OK;
第2階段是阻塞(sync blocking)的,即內(nèi)核空間和用戶(hù)空間之間復(fù)制數(shù)據(jù)是阻塞的;
淘米、煮飯我不等,我去玩會(huì),盛飯過(guò)程我等著你裝好飯,但是要等到盛好飯才算完事,這是同步的,結(jié)果就是盛好飯;
?
IO多路復(fù)用,multiplexing:
同時(shí)監(jiān)控多個(gè)IO,有一個(gè)準(zhǔn)備好了,就不需要等了,開(kāi)始處理,提高同時(shí)處理IO的能力;同時(shí)多路在等,而不是等完一個(gè)再等下一個(gè);2個(gè)階段均是sync blocking;
select,所有平臺(tái)支持,poll是select的升級(jí);
epoll,linux kernel2.5+支持,對(duì)select和poll的增強(qiáng),在監(jiān)視的基礎(chǔ)上,增加回調(diào)機(jī)制(通知機(jī)制);BSD、MAC的kqueue;win的iocp;
通常用multiplexing;
以select為例,將關(guān)注的IO操作告訴select函數(shù)并調(diào)用,進(jìn)程阻塞,內(nèi)核監(jiān)視select關(guān)注的fd文件描述符,被關(guān)注的任何一個(gè)fd對(duì)應(yīng)的IO準(zhǔn)備好了數(shù)據(jù),select返回,在使用read將數(shù)據(jù)復(fù)制到用戶(hù)進(jìn)程;
例,食堂供應(yīng)很多菜(眾多的IO),你需要吃某三菜一湯,大師傅(OS)說(shuō)要現(xiàn)做,需要等,你只好等待,其中一樣菜好了,大師傅叫你過(guò)來(lái),你得自己找找看哪一樣菜好了,請(qǐng)服務(wù)員把做好的菜打給你,而epoll是有菜準(zhǔn)備好了,大師傅喊你去幾號(hào)窗口直接打菜,不用自己找菜了;
?
async異步IO:
linux的aio系統(tǒng)調(diào)用,從kernel version2.6開(kāi)始支持;
2階段都是異步,高并發(fā)時(shí)用;
進(jìn)程發(fā)起異步IO請(qǐng)求,立即返回,內(nèi)核完成IO的兩個(gè)階段,內(nèi)核給進(jìn)程發(fā)一個(gè)信號(hào);
例,來(lái)打飯,跟大師傅說(shuō)飯好了叫我,飯菜準(zhǔn)備好了,窗口服務(wù)員把飯盛好了打電話叫你,兩階段都是異步的,在整個(gè)過(guò)程中,進(jìn)程都可以忙別的,等好了才過(guò)來(lái);
例,今天不想出去到飯店吃了,點(diǎn)外賣(mài),飯菜在飯店做好了(第1階段),快遞員把飯送到你家門(mén)口(第2階段);
?
?
?
select庫(kù):
實(shí)現(xiàn)了select、poll系統(tǒng)調(diào)用,部分實(shí)現(xiàn)了epoll;
是底層的IO多路復(fù)用模塊,類(lèi)似網(wǎng)絡(luò)編程的socket;
?
開(kāi)發(fā)中選擇:
1、完全跨平臺(tái),使用select、poll,但性能較差;
2、針對(duì)不同OS自行選擇支持的技術(shù),這樣做會(huì)提高IO處理的性能;
?
selectors庫(kù):
py3.4提供,高級(jí)IO復(fù)用庫(kù);
?
類(lèi)層次結(jié)構(gòu):
BaseSelector
???????? SelectSelector
???????? PollSelector
???????? EpollSelector
???????? DevpollSelector
???????? KqueueSelector
?
selectors.DefaultSelector(),返回當(dāng)前平臺(tái)最有效、性能最高的實(shí)現(xiàn);
但,此庫(kù)沒(méi)有實(shí)現(xiàn)win的iocp,將自動(dòng)退化為select;
?
?
class BaseSelector(metaclass=ABCMeta):
??? @abstractmethod
??? def register(self, fileobj, events, data=None):?? #fileobj,被監(jiān)視文件對(duì)象,如socket對(duì)象;events,該文件對(duì)象必須等待的事件;data,可選,與此文件對(duì)象相關(guān)聯(lián)的不透明數(shù)據(jù),如,可用來(lái)存儲(chǔ)每個(gè)客戶(hù)端的會(huì)話ID,本例中關(guān)聯(lián)方法,就是讓selector干什么事,可以是任意對(duì)象,如果是函數(shù)類(lèi)似回調(diào)
?
events常量:
EVENT_READ,可讀0x01,內(nèi)核已準(zhǔn)備好輸入輸出設(shè)備,可以開(kāi)始讀了;
EVENT_WRITE,可寫(xiě)0x10,內(nèi)核已準(zhǔn)備好,可以往里寫(xiě)了;
?
注:
# generic events, that must be mapped to implementation-specific ones
EVENT_READ = (1 << 0)
EVENT_WRITE = (1 << 1)
?
單線程+selectors,單線程下用selectors而不用多線程,條件不滿足不能轉(zhuǎn)為就緒態(tài),則不會(huì)被cpu調(diào)度;
多線程+阻塞,在OS中多了線程資源而已;
selectors可解決網(wǎng)絡(luò)IO、文件IO;
?
?
例:
selector = selectors.DefaultSelector()
?
def accept(sock: socket.socket):
??? conn, addrinfo = sock.accept()
??? conn.setblocking(False)
??? selector.register(conn, selectors.EVENT_READ, recv)
?
def recv(conn: socket.socket):
??? data = conn.recv(1024).strip().decode()
??? print(data)
??? msg = 'ack: {}'.format(data)
??? conn.send(msg.encode())
?
sock = socket.socket()
addr = ('127.0.0.1', 9999)
sock.bind(addr)
sock.listen()
sock.setblocking(False)
?
e = threading.Event()
?
key = selector.register(sock, selectors.EVENT_READ, accept)
print(key)
?
while not e.is_set():
??? events = selector.select()
??? if events:
??????? print(type(events))
?????????????????? print(events)
??? for key,mask in events:
??????? print(key, mask)
??????? callback = key.data
??????? callback(key.fileobj)
輸出:
SelectorKey(fileobj=
[(SelectorKey(fileobj=
SelectorKey(fileobj=
[(SelectorKey(fileobj=
SelectorKey(fileobj=
nimeide
?
?
例:
ChatServer改為IO多路復(fù)用方式;
?
注:
if mask == selectors.EVENT_READ:?? #不嚴(yán)格
if (mask & selectors.EVENT_READ) == selectors.EVENT_READ:?? #嚴(yán)格寫(xiě)法,如果r和w同時(shí)滿足,進(jìn)來(lái)3則不作處理
?
?
?
?