1. 程式人生 > >多工版——程序

多工版——程序

程序的概念

程序可以通俗的理解為一個執行的程式或者軟體,程序是作業系統資源分配的基本單位。

多程序完成多工

# 匯入執行緒模組
import multiprocessing
import time

# 多程序完成多工
def run():
    '''子程序需要執行的程式碼'''
    while True:
        print('-----2-----')
        time.sleep(1)

if __name__ == '__main__':
    # 建立子程序
    sub_process = multiprocessing.Process(target=run)
    # 啟動子程序
    sub_process.start()
    while True:
        print('-----1-----')
        time.sleep(1)

說明:

Process程序類的引數
	給程序傳參的方式同線程一樣,有兩種方式,args用元組的方式,kwargs用字典的方式,name可以指定程序名,target指定任務名,group指定程序組,目前只能用None。
獲取當前的程序:multiprocess.current_process()
獲取當前程序的編號:current_process.pid     os.getpid()
獲取父程序的編號:os.getppid()
根據程序的編號殺死程序:os.kill(os.getpid(),9)
程序名.join():主程序等待子程序執行完成程式碼才繼續執行
程序名.termiante():銷燬子程序
守護主程序:程序名.daemon = True

注意:

1.程序之間是不共享全域性變數的。建立子程序其實就是對主程序的拷貝,程序之間相互獨立,訪問的全域性變數不是同一個。
2.主程序會等待所有的子程序執行結束後才退出。

程序之間的通訊 Queue

程序之間的通訊可以通過multiprocessing的Queue模組來完成資料傳遞,Queue本身就是一個訊息佇列。
import multiprocessing
import time
	
# 寫入資料
def write_data(queue):
    for i in range(10):
        if queue.full():
            print("佇列滿了")
            break
        queue.put(i)
        time.sleep(0.2)
        print(i)


# 讀取資料
def read_data(queue):
    while True:
        # 加入資料從佇列取完了,那麼跳出迴圈
        if queue.qsize() == 0:
            print("佇列空了")
            break
        value = queue.get()
        print(value)


if __name__ == '__main__':
    # 建立訊息佇列
    queue = multiprocessing.Queue(5)
  

# 建立寫入資料的程序
write_process = multiprocessing.Process(target=write_data, args=(queue,))
# 建立讀取資料的程序
read_process = multiprocessing.Process(target=read_data, args=(queue,))

# 啟動程序
write_process.start()
# 主程序等待寫入程序執行完成以後程式碼再繼續往下執行
write_process.join()
read_process.start()

執行結果:

0
1
2
3
4
佇列滿了
0
1
2
3
4
佇列空了

解釋:

在初始化Queue物件的時候,我們可以指定可接收的最大可接收的訊息數量,若沒有指定或數量為負,那麼就代表可接受的訊息數量沒有上限。
Queue.qsize():返回當前佇列包含的訊息數量;
Queue.empty():如果佇列為空,返回True,反之False , 注意這個操作是不可靠的。
Queue.full():如果佇列滿了,返回True,反之False;
Queue.get([block[, timeout]]):獲取佇列中的一條訊息,然後將其從列隊中移除,block預設值為True;
1)如果block使用預設值,且沒有設定timeout(單位秒),訊息列隊如果為空,此時程式將被阻塞(停在讀取狀態),直到從訊息列隊讀到訊息為止,如果設定了timeout,則會等待timeout秒,若還沒讀取到任何訊息,則丟擲"Queue.Empty"異常;
2)如果block值為False,訊息列隊如果為空,則會立刻丟擲"Queue.Empty"異常;
Queue.get_nowait():相當Queue.get(False);
Queue.put(item,[block[, timeout]]):將item訊息寫入佇列,block預設值為True;
1)如果block使用預設值,且沒有設定timeout(單位秒),訊息列隊如果已經沒有空間可寫入,此時程式將被阻塞(停在寫入狀態),直到從訊息列隊騰出空間為止,如果設定了timeout,則會等待timeout秒,若還沒空間,則丟擲"Queue.Full"異常;
2)如果block值為False,訊息列隊如果沒有空間可寫入,則會立刻丟擲"Queue.Full"異常;
Queue.put_nowait(item):相當Queue.put(item, False);

程序池Pool

程序池會根據使用者的任務執行情況自動建立程序,而且儘量少建立程序,合理利用程序池中的程序完成多工。

程序池同步執行多工

同步執行任務表示池中的任務在執行任務的時候一個任務執行完成才會執行下一個任務,如果沒有執行完會等待。
import multiprocessing
import time


# 拷貝任務
def work():
    print("複製中...", multiprocessing.current_process().pid)
    time.sleep(0.5)

if __name__ == '__main__':
    # 建立程序池
    # 3:程序池中程序的最大個數,如果不執行最大程序池的可建立程序的個數,預設是建立自己電腦cpu的核數。
    pool = multiprocessing.Pool(3)
    # 模擬大批量的任務,讓程序池去執行
    for i in range(5):
        # 迴圈讓程序池執行對應的work任務
        # 同步執行任務,一個任務執行完成以後另外一個任務才能執行
        pool.apply(work)
執行結果:

複製中... 100512
複製中... 68128
複製中... 98924
複製中... 100512
複製中... 68128

程序池非同步執行多工

非同步執行多工表示程序池中的程序同時執行任務,程序之間不會相互等待。
import multiprocessing
import time


# 拷貝任務
def work():
    print("複製中...", multiprocessing.current_process().pid)
    # 獲取當前程序的守護狀態
    # 提示:使用程序池建立的程序是守護主程序的狀態,預設自己通過Process建立的程序是不是守住主程序的狀態
    # print(multiprocessing.current_process().daemon)
    time.sleep(0.5)

if __name__ == '__main__':
    # 建立程序池
    # 3:程序池中程序的最大個數
    pool = multiprocessing.Pool(3)
    # 模擬大批量的任務,讓程序池去執行
    for i in range(5):
        # 迴圈讓程序池執行對應的work任務
        # 同步執行任務,一個任務執行完成以後另外一個任務才能執行
        # pool.apply(work)
        # 非同步執行,任務執行不會等待,多個任務一起執行
        pool.apply_async(work)

    # 關閉程序池,意思告訴主程序以後不會有新的任務新增進來
    pool.close()
    # 主程序等待程序池執行完成以後程式再退出
    pool.join()
執行結果:

複製中... 122872
複製中... 61772
複製中... 114636
複製中... 122872
複製中... 114636

注意:

同步執行任務的時候主程序會等待子程序結束之後再結束程序,非同步執行的時候不是,非同步執行是守護主程序的,即Process類中的daemon設定預設為True。在設定守護主程序的時候,一定的要有關閉程序池的過程,表名不會在新增別的程序任務 。