Python Day 32 進程和程序的區別、阻塞 非阻塞 並行 併發、進程的三種狀態、進程的建立和銷燬、python中兩種方式實現多進程、進程間內存相互隔離、join函數孤兒進程與殭屍進程

  ##內容回顧python

# UDP協議  

​    用戶數據報協議,是OSI模型中屬於傳輸層的協議 

​    提供,不可靠的,不要求順序的,數據量小的,速度快的傳輸服務 

​    不可靠:

​        發送完成後不須要確認信息 而且當即刪除緩存中的數據 

​    不要求順序:

​        當一個數據較大時 會分爲多個數據報來傳輸,對方沒法獲知數據的順序,以及是否完整

​    數據量較小的:

​        數據越大丟包的可能性越高 ,建議的數據量不要超過1472

​    速度快:

​        相對於TCP而言快不少 不須要確認信息 ,也不須要創建連接 

# 通信流程

​    若是TCP比喻爲手機打電話的過程 那麼UDP能夠看作是對講機   

​    1.買機器    建立UDP的socket 

​    2.固定頻道    bind一個ip和端口

​    3.收發數據      recvfrom   sendto 

​    

​    接收

​    1.買機器    建立UDP的socket 

​    2.收發數據      recvfrom   sendto 

​        注意 不能先收    要收數據 必須明確端口號  沒有端口號是不可能使用網絡服務的 



​    

###TCP  與 UDP 的其餘區別

1.沒有鏈接  

2.不會粘包     每次發送都是一個獨立的數據包    



TCP 對數據完整性要求較高 : 在線支付  ,文字信息 

 UDP: 對數據不要求完整性 可是要快 :  視頻 語音 遊戲  

# DNS 

域名解析服務器  

域名 就是一串有規律的字符串  ,用於綁定IP,目的是爲了方便記憶 

域名解析服務器    就是幫你將域名轉換爲ip地址  

本質就是一個數據庫  裏面存的就是域名和ip對應關係   

一臺機器性能有限

分爲 

​    根域名服務器        只存儲定義域名服務器的信息  

​    頂級域名服務器 只存儲二級域名服務器的信息  

​    二級域名服務器    二級存三級 

​    三級域名   三級能夠存四級  一般直接存儲具體的ip信息  

​    .....................

​    本地DNS  用於加速解析    



###本身搭建DNS 的做用
1.CDN     內容分發網絡       就是在你的周圍創建更多鏡像服務    

​    2.集羣   

# 操做系統

也是一個軟件, 

​    受保護的不能隨意修改  

​    代碼量巨大  內核在500萬以上 

​    長壽 ,一旦完成通常不改 

​    linux是脫襪子  將(shell 保留解釋權!)  移植到minux上 結合產生的 

###操做系統的做用:

1.將複雜醜陋的硬件細節隱藏起來,提供了簡單的調用接口 

2.將應用程序對於硬件的競爭變的有序  



###操做系統發展史  
1.第一帶計算機   真空管和穿孔卡片  沒有進程 沒有操做系統   

​    2.第二代計算機  7094 1401    晶體管  批處理系統 

​        輸入輸出  以及計算設備 不能互聯  須要人蔘與    一批一批的處理   開發效率慢  而且串行執行

​    3.第三代計算機    集成電路 與多道技術 

​        多終端聯機  spooling      同一臺機器既能進行科學計算  又能作字符處理       通用計算機

​        多道技術   解決串行致使的效率低下問題

​        多用戶終端    能夠同時爲多個用戶提供服務  每一個用戶覺得本身獨享一臺計算機   

​    4.第四代   我的電腦

​        大規模使用了集成電路,大多都提供了GUI界面  

# 多道技術   

​    產生背景 ,全部程序串行 致使資源浪費   

​    目的是讓多個程序能夠併發執行  , 同時處理多個任務   

## 關鍵技術

### 空間複用

指的是 同一時間 內存中加載多個不一樣程序數據,

每一個進程間內存區域相互隔離,物理層面的隔離  

### 時間複用       切換 + 保存

    # 切換條件:

    1.一個進程執行過程當中遇到了IO操做  切換到其餘進程

    2.運行時間過長,會被操做系統強行剝奪執行權力   

單純的切換不夠,必須在切換前保存當前的狀態,以便於恢復執行  



# 進程

一個正在被運行的程序就稱之爲進程,是程序具體執行過程,一種抽象概念

進程來自於操做系統  

  ##多進程linux

# 進程和程序的區別  
「」「

程序就是一堆計算機能夠識別文件,程序在沒有被運行就是躺在硬盤上的一堆二進制

運行程序時,要從硬盤讀取數據到內存中,CPU從內存讀取指令並執行 ,

一旦運行就產生了進程    

一個程序能夠屢次執行 產生多個進程,可是進程之間相互獨立

當咱們右鍵運行了一個py文件時 ,其實啓動的是python解釋器,你的py文件實際上是看成參數傳給瞭解釋器   

」「」

# 阻塞  非阻塞   並行  併發   (重點)
「」「
#一、阻塞與非阻塞指的是程序的兩種運行狀態
# 阻塞:遇到IO就發生阻塞,程序一旦遇到阻塞操做就會停在原地,而且馬上釋放CPU資源
  本地IO input      print     sleep    read  write      

​    網絡IO recv  send

# 非阻塞(就緒態或運行態):沒有遇到IO操做,或者經過某種手段讓程序即使是遇到IO操做也不會停在原地,執行其餘操做,力求儘量多
併發: 多個任務看起來同時在處理 ,本質上是切換執行 速度很是快 並行: 多個任務真正的同時執行 必須具有多核CPU 纔可能並行 併發 並行 說的是 任務的處理方式 」「」

  ##進程的三種狀態nginx

#就緒態,運行態,和阻塞態

多道技術會在進程執行時間過長或遇到IO時自動切換其餘進程,意味着IO操做與進程被剝奪CPU執行權都會形成進程沒法繼續執行

 

  ##程序員的永恆話題程序員

提升效率

根本方法就是讓程序儘量處於運行狀態

減小IO  儘量多佔用CPU時間     

緩衝區就是用於減小IO操做的

  ##進程的建立和銷燬(瞭解)web

### 進程的建立

但凡是硬件,都須要有操做系統去管理,只要有操做系統,就有進程的概念,就須要有建立進程的方式,一些操做系統只爲一個應用程序設計,好比微波爐中的控制器,一旦啓動微波爐,進程就已經存在。

  而對於通用系統(跑不少應用程序),須要有系統運行過程當中建立或撤銷進程的能力,主要分爲4中形式建立新的進程

1. 系統初始化(查看進程linux中用ps命令,windows中用任務管理器,前臺進程負責與用戶交互,後臺運行的進程與用戶無關,運行在後臺而且只在須要時才喚醒的進程,稱爲守護進程,如電子郵件、web頁面、新聞、打印)
2. 一個進程在運行過程當中開啓了子進程(如nginx開啓多進程,os.fork,subprocess.Popen等)
3. 用戶的交互式請求,而建立一個新進程(如用戶雙擊暴風影音)
4. 一個批處理做業的初始化(只在大型機的批處理系統中應用)

### 進程的銷燬

1. 正常退出(自願,如用戶點擊交互式頁面的叉號,或程序執行完畢調用發起系統調用正常退出,在linux中用exit,在windows中用ExitProcess)
2. 出錯退出(自願,python a.py中a.py不存在)
3. 嚴重錯誤(非自願,執行非法指令,如引用不存在的內存,1/0等,能夠捕捉異常,try...except...)
4. 被其餘進程殺死(非自願,如kill -9### 進程的層次結構

不管UNIX仍是windows,進程只有一個父進程,不一樣的是:

1. 在UNIX中全部的進程,都是以init進程爲根,組成樹形結構。父子進程共同組成一個進程組,這樣,當從鍵盤發出一個信號時,該信號被送給當前與鍵盤相關的進程組中的全部成員。
2. 在windows中,沒有進程層次的概念,全部的進程都是地位相同的,惟一相似於進程層次的暗示,是在建立進程時,父進程獲得一個特別的令牌(**稱爲句柄**),該句柄能夠用來控制子進程,可是父進程有權把該句柄傳給其餘子進程,這樣就沒有層次了。

  ##python中實現多進程shell

「」「
在一個應用程序中可能會有多個任務須要併發執行,可是對於操做系統而言,一個進程就是一個任務,CPU會從上往下依次執行代碼,當代碼中遇到IO操做時,操做系統就會剝奪CPU執行權給其餘應用程序,這樣對於當前應用程序而言,效率就下降了,如何使得程序既能完成任務又不下降效率呢?答案就是讓把當前程序中的耗時操做交給子進程來完成,如此當前應用程序能夠繼續執行其餘任務!
」「」

#python中開啓子進程的兩種方式

#方式一:直接實例化Process  ,將要執行任務用target傳入
from multiprocessing import Process
import os
import time
# 爲何要子進程   當出現一些耗時較長的操做時 會致使程序進入阻塞狀態  二沒法執行其餘代碼
# 這時候就能夠開啓子進程把任務交給他

def task(name):
    print(" name %s 子進程run!" % name)
    # print("son is :%s" % os.getpid())
    # print("father is :%s" % os.getppid())
    time.sleep(3)
    print("子進程 over!")


if __name__ == '__main__':
    print("father :%s" % os.getpid())
    p = Process(target=task,args=("rose",))
    p.start() # 開啓子進程   本質是向操做系統發送請求 讓它啓動進程    一般不可能當即開啓
    print("任務結束!")

"""
windows  和  linux 開啓進程的方式不一樣 
首先相同之處都是 須要將數據copy一份給子進程   這樣子進程才知道要幹什麼  
linux 會將父進程的全部數據 徹底copy    
windows  會copy 一部分數據   同時會導入py文件來執行   這樣一來遞歸開進程    
linux 拿到父進程知道代碼位置 繼續執行   
建議都加上判斷  能夠保證兩個平臺都能用  

記住:
開啓進程的代碼 都把它放到  if __name__ == "__main__": 中便可


"""


#方式二:繼承Process類 ,覆蓋run方法  將任務放入run方法中 (重點掌握) 
import os
from multiprocessing import  Process
class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name = name
    # 繼承Procee覆蓋run方法將要執行任務發到run中
    def run(self):
        print(self.name)
        print("子進程 %s running!" % os.getpid())
        print("子進程 %s over!" % os.getpid())

if __name__ == '__main__':
    # 建立時 不用再指定target參數了
    p = MyProcess("rose")
    p.start()
    print("父進程over!")

  ##進程間內存相互隔離數據庫

from multiprocessing import Process
import time
name = "青椒"
def task():
    global name
    name = "rose"
    print("改完了!")
    print("子進程的%s" % name)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    time.sleep(2)
    print(name)

  ##join函數windows

「」「
調用start函數後的操做就由操做系統來玩了,至於什麼時候開啓進程,進程什麼時候執行,什麼時候結束都與應用程序無關,因此當前進程會繼續往下執行,join函數就能夠是父進程等待子進程結束後繼續執行,即用於提升子進程優先級 ,使得父進程等待子進程結束  
」「」

#案例
"""
    當你開啓了一個子進程 而且給他一個任務  若是你但願知道這個任務何時完成 那就須要等待

"""
import time,os
from multiprocessing import Process
# def task(i):
#     # print(" %s 買菸去了" % i)
#     time.sleep(3)
#     print("%s 買完了!" % i)
#
# if __name__ == '__main__':
#     # p = Process(target=task)
#     # p.start()
#     # # time.sleep(5)
#     # p.join() # 等待子進程執行完畢   將子進程的優先級提升
#     #
#
#
#
#     for i in range(10):
#         p = Process(target=task,args=(i,))
#         p.start()  # 進程啓動順序  與start無關   主要看操做系統先切換誰
#         # p.join()
#
#     p.join()  # 最後一個
#
#
#     print("over!")


def task(i):
    # print(" %s 買菸去了" % i)
    time.sleep(i)
    print("%s 買完了!" % i)

if __name__ == '__main__':
    strat_time = time.time()
    p1 = Process(target=task,args=(1,))
    p2 = Process(target=task,args=(2,))
    p3 = Process(target=task,args=(3,))

    p1.start()
    p2.start()
    p3.start()

    p3.join() #3
    p2.join()
    p1.join()


    end_time = time.time()
    print(end_time - strat_time)
    print("over!")


#案例2
from multiprocessing import Process
import time,random
x=1000
def task(n):
    print('%s is runing' %n)
    time.sleep(n)
if __name__ == '__main__':
    start_time=time.time()
    p1=Process(target=task,args=(1,))
    p2=Process(target=task,args=(2,))
    p3=Process(target=task,args=(3,))
    p1.start()
    p2.start()
    p3.start()
    p3.join() #3s
    p1.join()
    p2.join()
    print('主',(time.time() - start_time))
    start_time=time.time()
    p_l=[]
    for i in range(1,4):
        p=Process(target=task,args=(i,))
        p_l.append(p)
        p.start()
    for p in p_l:
        p.join()
   
    print('主',(time.time() - start_time))

  ##Process對象經常使用屬性瀏覽器

from multiprocessing import  Process
import time,os
def task():
    print("121121")
    # time.sleep(10)
    # print("over")
    # print(os.getppid())
    exit(1000)

if __name__ == '__main__':
    p = Process(target=task,name="rose")
    p.start() # 懶加載優化機制  若是沒有調用start 那麼該對象將不會被建立
    time.sleep(1)
    # p.join() # 等待子進程結束
    # p.terminate()  # 終止進程
    # print(p.name)  # 進程的名稱
    # print(p.is_alive()) #是否存活
    # p.terminate() # 與start同樣 都是給操做系統發送指令 因此會有延遲
    # print(p.is_alive())
    # print(p.pid)
    # print(p.exitcode) # 獲取退出碼

  ##孤兒進程與殭屍進程緩存

## 孤兒進程

指的是,父進程先結束 ,而子進程還在運行着, 

孤兒進程無害,有 其存在的必要性 

例如:qq開啓了瀏覽器,qq先退出了  瀏覽器應該繼續運行  

孤兒進程會被操做系統接管    



## 殭屍進程

值得是,子進程已經結束了,可是操做系統會保存一些進程信息,如PID,運行時間等,此時這個進程就稱之爲殭屍進程  

殭屍進程若是太多將會佔用大量的資源,形成系統沒法開啓新新進程 

linux 中有一個wai/waitpid 用於父進程回收子進程資源

python會自動回收殭屍進程  
相關文章
相關標籤/搜索