一 操做系統的做用:python
1:隱藏醜陋複雜的硬件接口,提供良好的抽象接口算法
2:管理、調度進程,而且將多個進程對硬件的競爭變得有序編程
二 多道技術: json
1.產生背景:針對單核,實現併發windows
ps:安全
如今的主機通常是多核,那麼每一個核都會利用多道技術多線程
有4個cpu,運行於cpu1的某個程序遇到io阻塞,會等到io結束再從新調度,會被調度到4個併發
cpu中的任意一個,具體由操做系統調度算法決定。app
2.空間上的複用:如內存中同時有多道程序dom
3.時間上的複用:複用一個cpu的時間片
強調:遇到io切,佔用cpu時間過長也切,核心在於切以前將進程的狀態保存下來,這樣 才能保證下次切換回來時,能基於上次切走的位置繼續運行
3、進程
進程:正在進行的一個過程或者說一個任務。而負責執行任務的則是cpu
程序:僅僅只是一堆代碼而已,而進程指的是程序的運行過程。
須要強調的是:同一個程序執行兩次,那也是兩個進程,好比打開暴風影音,雖然都是同一個軟件,可是一個能夠播放大話西遊,一個能夠播放海賊王。
關於multiprocess模塊——綜合的、多元的 進程模塊(包):python中建立進程用來替我作事。
import os from multiprocessing import Process #導入進程模塊 import time def func(): time.sleep(2) print('子進程號%d'%os.getpid()) if __name__ =='__main__': p=Process(target=func) p.start() #啓動子進程 print('第一次主進程號%d'%os.getpid()) p.join() #阻塞 print('第二次主進程號%d'%os.getpid())
有兩種狀況:
一、沒有p.join() :這種狀況下不阻塞,執行主程序,調用子進程。子進程和父進程是異步執行。
建立進程對象 傳要執行的函數 以及參數 進程對象.start() 主進程和子進程就是異步執行 若是主進程中的代碼已經結束了,子進程還沒結束,主進程會等待子進程 p.join 就是主進程會阻塞在join的位置,等待p進程結束 windows操做系統中 建立進程的語句必定要放在if __name__ == '__main__':條件語句下面
二、有p.join():主進程阻塞在join的位置,等待p進程的結束(異步阻塞)
二、開啓多個子進程
import os import time from multiprocessing import Process def func(i): time.sleep(3) print('%d :子進程%d乾的事,父進程%d乾的事'%(i,os.getpid(),os.getppid())) if __name__=='__main__': p_lst=[] for i in range(10): p=Process(target=func,args=(i,)) #實例化,調用線程類,傳參數 p.start() #啓動線程(相似傳達一下消息 p_lst.append(p) for p in p_lst: p.join() #阻塞 print('-------主進程-------')
建立一個線程,而後啓動(對象名.start),它會在未知的時間裏建立線程,因此至於它是否是在主線程以前仍是以後啓動都不能肯定。若是想要主線程在全部線程後等待,那麼須要預先建立一個空列表,而後把全部啓動的子線程放入列表中,對列表中的子線程整體進行循環阻塞後,啓動主線程。
三、另外一種開啓多進程的方法
import os from multiprocessing import Process class MyProcess(Process): #必須建立一個類,必須繼承Process方法 def run(self): #必須實現run方法 print('子進程%d'%os.getpid()) self.walk() def walk(self): print('子進程walk%d'%os.getpid()) if __name__ =='__main__': p=MyProcess() #先實例化一個對象 p.start() #啓動子進程 p.join() print('主進程%d'%os.getpid()) #主進程
4.守護進程
守護進程:守護進程會隨着主進程的代碼的結束而結束
守護進程的做用:會隨着主進程的代碼執行結束而結束,不會等待其餘子進程
守護進程要在start以前設置,在守護進程(也是個子進程)中,不能再開啓子進程。
import time from multiprocessing import Process def func(): print('--'*10) time.sleep(15) print('--'*10) def cal_time(): while True: time.sleep(1) print('過去了1秒') if __name__ == '__main__': p = Process(target=cal_time) p.daemon = True # 必定在開啓進程以前設置 p.start() p2 = Process(target=func) # 15s p2.start() for i in range(100): # 10s time.sleep(0.1) print('*'*i) p2.join()
鎖Lock:
在併發編程中,爲了保證數據安全。加上鎖以後,每次須要等待數據被訪問完以後,才能繼續被其餘應用訪問。
import json import time import random from multiprocessing import Lock from multiprocessing import Process def search(i): with open('ticket') as f: print(i,json.load(f)['count']) def get(i): with open('ticket') as f: ticket_num = json.load(f)['count'] time.sleep(random.random()) if ticket_num > 0: with open('ticket','w') as f: json.dump({'count':ticket_num-1},f) print('%s買到票了'%i) else: print('%s沒票了'%i) def task(i,lock): search(i) # 查看票 lock.acquire() #須要鎖 get(i) # 搶票 lock.release() #釋放鎖 if __name__ == '__main__': lock = Lock() #實例化鎖 for i in range(20): # 20我的同時搶票 p = Process(target=task,args=(i,lock)) p.start()
信號量:一把鑰匙多個鎖,能夠容許幾個進程同時訪問數據(數量是有限制的)
from multiprocessing import Semaphore from multiprocessing import Process import time import random def sing(i,sem): sem.acquire() print('%d進入KTV'%i) time.sleep(random.randint(1,10)) print('%d離開ktv'%i) sem.release() if __name__ =='__main__': sem=Semaphore(4) for i in range(20): Process(target=sing,args=(i,sem)).start()
4、併發與並行
不管是並行仍是併發,在用戶看來都是'同時'運行的,不論是進程仍是線程,都只是一個任務而已,真是幹活的是cpu,cpu來作這些任務,而一個cpu同一時刻只能執行一個任務
1 併發:是僞並行,即看起來是同時運行。單個cpu+多道技術就能夠實現併發,(並行也屬於併發)
2 並行:同時運行,只有具有多個cpu才能實現並行
單核下,能夠利用多道技術,多個核,每一個核也均可以利用多道技術(多道技術是針對單核而言的)
有四個核,六個任務,這樣同一時間有四個任務被執行,假設分別被分配給了cpu1,cpu2,cpu3,cpu4,
一旦任務1遇到I/O就被迫中斷執行,此時任務5就拿到cpu1的時間片去執行,這就是單核下的多道技術
而一旦任務1的I/O結束了,操做系統會從新調用它(需知進程的調度、分配給哪一個cpu運行,由操做系統說了算),可能被分配給四個cpu中的任意一個去執行
全部現代計算機常常會在同一時間作不少件事,一個用戶的PC(不管是單cpu仍是多cpu),均可以同時運行多個任務(一個任務能夠理解爲一個進程)。
啓動一個進程來殺毒(360軟件)
啓動一個進程來看電影(暴風影音)
啓動一個進程來聊天(騰訊QQ)
全部的這些進程都需被管理,因而一個支持多進程的多道程序系統是相當重要的
多道技術概念回顧:內存中同時存入多道(多個)程序,cpu從一個進程快速切換到另一個,使每一個進程各自運行幾十或幾百毫秒,這樣,雖然在某一個瞬間,一個cpu只能執行一個任務,但在1秒內,cpu卻能夠運行多個進程,這就給人產生了並行的錯覺,即僞併發,以此來區分多處理器操做系統的真正硬件並行(多個cpu共享同一個物理內存)
5、同步/異步和阻塞/非阻塞
同步:就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不會返回。按照這個定義,其實絕大多數函數都是同步調用。可是通常而言,咱們在說同步、異步的時候,特指那些須要其餘部件協做或者須要必定時間完成的任務。
異步:當一個異步功能調用發出後,調用者不能馬上獲得結果。當該異步功能完成後,經過狀態、通知或回調來通知調用者。若是異步功能用狀態來通知,那麼調用者就須要每隔必定時間檢查一次,效率就很低(有些初學多線程編程的人,總喜歡用一個循環去檢查某個變量的值,這實際上是一 種很嚴重的錯誤)。若是是使用通知的方式,效率則很高,由於異步功能幾乎不須要作額外的操做。至於回調函數,其實和通知沒太多區別。
阻塞:是指調用結果返回以前,當前線程會被掛起(如遇到io操做)。函數只有在獲得結果以後纔會將阻塞的線程激活。有人也許會把阻塞調用和同步調用等同起來,實際上他是不一樣的。對於同步調用來講,不少時候當前線程仍是激活的,只是從邏輯上當前函數沒有返回而已。
非阻塞:指在不能馬上獲得結果以前也會馬上返回,同時該函數不會阻塞當前線程。
小結:
1. 同步與異步針對的是函數/任務的調用方式:同步就是當一個進程發起一個函數(任務)調用的時候,一直等到函數(任務)完成,而進程繼續處於激活狀態。而異步狀況下是當一個進程發起一個函數(任務)調用的時候,不會等函數返回,而是繼續往下執行當,函數返回的時候經過狀態、通知、事件等方式通知進程任務完成。
2. 阻塞與非阻塞針對的是進程或線程:阻塞是當請求不能知足的時候就將進程掛起,而非阻塞則不會阻塞當前進程