1. 程式人生 > 實用技巧 >十、多程序

十、多程序

一、程序基礎

馮諾依曼體系:

程式和系統:一個系統一般由多個程式構成。如:Win10系統由程序管理程式、記憶體管理程式、N個驅動程式等構成。

作業系統的作用:與硬體互動,為使用者程式提供安全、穩定的執行環境,提供大量的API供使用者程式使用。

任務:開啟某個軟體、瀏覽網頁、下載電影、聽音樂、玩遊戲……每個應用程式被稱為一個任務。

單任務:只能有一個任務在進行(DOS系統)

多工:可以有多個任務同時進行(Win10系統)

CPU時間片:程式的執行依賴於CPU,CPU把自己進行時間上的分割,每個程式輪流佔用CPU。時間片一般是切換所需時間的100倍。
0.01us 執行 A 0.02us 執行B 時間片輪轉

單核: 同一時間,只能有一個程式 在使用CPU

分時作業系統:以時間片輪轉的方式,讓一臺計算機為多個終端服務。 (多使用者)

程序:應用程式的動態執行過程。(Process:(為達到某一目標的)過程;程序;流程、過程、步驟;)

  • 網易雲音樂 (軟體)
  • cloudmusic.exe(程序)
  • 過程: 啟動 -> 軟體程式碼要載入到記憶體--> CPU為程序建立“檔案” --> 等CPU時間片 -- > 退出
  • 軟體只有執行才能生成程序
  • 1個軟體可以生成1~n個程序

二、程序的狀態:執行、等待、就緒

  • PCB: 程序控制塊(PCB Process Control Block),是作業系統中最重要的記錄性資料結構。它是程序管理和控制的最重要的資料結構,每 一個程序均有一個PCB
  • 建立狀態:程序在建立時需要申請一個空白PCB,向其中填寫控制和管理程序的資訊,完成資源分配。如果建立工作無法完成,比如資源無 法滿足,就無法被排程執行,把此時程序所處狀態稱為建立狀態
  • 就緒狀態:Ready to run。建立程序後,程序進入就緒狀態(即程序被載入到主記憶體中)這裡的程序已經準備好執行,正在等待獲取執行它的CPU時間。準備由CPU執行的程序在佇列中維護以備處理。
  • 執行狀態:程序由CPU選擇執行,程序中的指令由任何一個可用的CPU核心執行。
  • 阻塞狀態:每當程序請求訪問I/O或需要使用者輸入,它將進入阻塞或等待狀態。程序繼續在主記憶體中等待,不需要CPU。一旦I/O操作完成,程序將進入就緒狀態。
  • 終止狀態:程序被終止,PCB也被刪除。

作業系統管理程序:分配記憶體給程序,分配CPU時間片給程序,儲存程序資訊(使用PID標識程序,為程序設定優先順序,記錄程序狀態,記錄I/O狀態等

如何人為地改變程序的狀態:可以通過訊號修改程序的狀態。taskkill /f /PID8899 taskkill /f /t /im Typora.exe 殺程式

三、建立並執行程序

在Python中,執行一個Python指令碼,就會建立一個程序。

可以用os.getpid()獲得程序的PID

如何建立2個程序? multiprocessing.Process建立程序

關於daemon:

  • 設定daemon = True,主程序執行完,不會等待該程序
  • 設定daemon = False,主程序執行完,會等待該程序執行完再退出

關於join:

  • p1.json()
  • 主程序會等p1執行完再執行剩下的程式碼。
import os
import time
from multiprocessing import Process


def cloudmusic():
    """模擬網易雲音樂的程序"""
    for i in range(5):
        print(f"子程序{os.getpid()}正則播放 無人之島...")
        time.sleep(1)


def lol():
    """模擬lol程序"""
    for i in range(8):
        print(f"子程序{os.getpid()}遊戲中,請勿打擾...")
        time.sleep(1)


def process_test():
    start_time = time.time()
    # 建立網易雲音樂程序
    # 在主程序中通過Process類建立的程序物件就是子程序
    p1 = Process(target=cloudmusic)
    p2 = Process(target=lol)
    # 設定daemon = True,主程序執行完,不會等待該程序
    # 設定daemon = False,主程序執行完,會等待該程序執行完再退出
    p1.daemon = True
    p2.daemon = False
    print(f"我是主程序,我的程序id是{os.getpid()}")
    p1.start()  # 啟動子程序p1
    p2.start()  # 啟動子程序p2
    p1.join()
    # p2.join()
    end_time = time.time()
    print(end_time - start_time)  # 這是主程序中最後1行程式碼,執行完,主程序結束


if __name__ == '__main__':
    process_test()
    # start_time = time.time()
    # lol()
    # cloudmusic()
    # end_time = time.time()
    # print(end_time - start_time)

四、程序的全域性變數

每建立一個程序,CPU都會單獨分配資源

所以,多個程序不會共享全域性變數

from multiprocessing import Process

result = 0


def work01():
    global result
    result += 1
    print(f'work01中result值是{result}')


def work02():
    global result
    result += 1
    print(f'work02中result值是{result}')


def main():
    work01()
    work02()
    print(result)


def process_test():
    p1 = Process(target=work01)
    p2 = Process(target=work02)
    p1.start()
    p2.start()
    p1.join()
    p2.join()


if __name__ == '__main__':
    process_test()
    print(f'主程序中result的值是:{result}')

'''
work01中result值是1
work02中result值是1
主程序中result的值是:0
'''

五、多程序中使用佇列共享資料

多程序中如何使用佇列共享資料?

答: 多個程序共享主程序中建立的佇列即可。主程序建立佇列,然後把隊列當做引數傳給每個子程序即可。

from multiprocessing import Process, Queue


def work01(q):
    print(id(q))
    r = q.get()
    r += 1
    q.put(r)
    print(f'work01中q值是{r}')


def work02(q):
    print(id(q))
    r = q.get()
    r += 1
    q.put(r)
    print(f'work02中q值是{r}')


def process_test():
    q = Queue()
    q.put(0)
    p1 = Process(target=work01, args=(q,))
    p2 = Process(target=work02, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print(f'主程序中q的值是:{q.get()}')


if __name__ == '__main__':
    process_test()