Python網路程式設計——程式

TechLee發表於2018-06-24

個人獨立部落格:www.limiao.tech
微信公眾號:TechBoard


程式

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

一個程式至少有一個程式,一個程式至少有一個執行緒,多程式可以完成多工

程式的狀態

工作中,任務數往往大於cpu的核數,即一定有一些任務正在執行,而另外一些任務在等待cpu進行執行,因此導致了有了不同的狀態

程式的使用

匯入程式模組:

import multiprocessing

用程式完成多工

import multiprocessing
import time


def sing():
    for i in range(10):
        print("唱歌中...")
        time.sleep(0.2)

def dance():
    for i in range(10):
        print("跳舞中...")
        time.sleep(0.2)

if __name__ == "__main__":
    # 建立對應的子程式執行對應的任務
    sing_process = multiprocessing.Process(target=sing)
    dance_process = multiprocessing.Process(target=dance)

    # 啟動程式執行對應的任務
    sing_process.start()
    dance_process.start()

Process類引數介紹
import multiprocessing
import os


def show_info(name,age):
    print("show_info:", multiprocessing.current_process())
    
    # 獲取程式的編號
    pritn("show_info pid:", multiprocessing.current_process().pid, os.getpid)
    print(name, age)

if __name__ == "__main__":
    # 建立子程式
    # group: 程式組,目前只能使用None
    # target: 執行的目標任務
    # args: 以元組方式傳參
    # kwargs: 以字典方式傳參
    sub_prcess = multiprocessing.Process(group=None, target=show_info, arg=("楊冪", 18))
    sub_prcess.start()

程式之間不共享全域性變數
import multiprocessing
import time


# 全域性變數
g_list = []

# 新增資料
def add_data():
    for i in range(15):
        g_list.append(i)
        time.sleep(0.1)
    print("add_data:", g_list)

# 讀取資料
def read_data():
    print("read_data:", g_list)

if __name__ == "__main__":
    # 建立新增資料的子程式
    add_process = multiprocessing.Process(target=add_data)
    # 建立讀取資料的子程式
    read_process = multiprocessing.Process(target=read_data)

    # 啟動程式
    add_process.start()
    # 主程式等待新增資料的子程式執行完成以後再執行讀取程式的操作
    add_process.join()
    # 程式碼執行到此說明新增資料的子程式把任務執行完成了
    read_process.start()

建立子程式其實就是對主程式資源的拷貝

主程式會等待所有的子程式執行完成程式再退出

import multiprocessing
import time


# 工作任務
def work():
    for i in range(10):
        print("工作中...")
        time.sleep(0.3)

if __name__ == "__main__":
    # 建立子程式
    sub_prcess = multiprocessing.Process(target=work)
    # 檢視程式的守護狀態
    # print(sub_prcess.daemon)
    # 守護主程式,主程式退出子程式直接銷燬,不再執行子程式裡面的程式碼
    # sub_prcess.daemon = True
    # 啟動程式執行對應的任務
    sub_process.start()

    # 主程式延時1s
    time.sleep(1)
    print("主程式執行完了")
    # 主程式退出之前把所有的子程式銷燬
    sub_prcess.terminate()
    exit()

總結: 主程式會等待所有的子程式執行完成程式再退出

獲取程式pid
# 獲取程式pid
import multiprocessing
import time
import os


def work():
    # 獲取當前程式編號
    print("work程式編號:", os.getpid())
    # 獲取父程式編號
    print("work父程式編號:", os.getppid())

    for i in range(10):
        print("工作中...")
        time.sleep(1)
        # 擴充套件:根據程式編號殺死對應的程式
        # os.kill(os.getpid(), 9)

if __name__ == `__main__`:
    # 獲取當前程式的編號:
    print("當前程式編號:", multiprocessing.current_process().pid)

    # 建立子程式
    sub_process = multiprocessing.Process(target=work)
    # 啟動程式
    sub_process.start()


    # 主程式執行列印資訊操作
    for i in range(20):
        print("我在主程式中執行...")
        time.sleep(1)
執行結果:

當前程式編號: 624
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
work程式編號: 1312
work父程式編號: 624
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...
我在主程式中執行...

***Repl Closed***
程式間通訊——Queue

可以使用multiprocessing模組Queue實現多程式之間的資料傳遞,Queue本身是一個訊息佇列程式

import multiprocessing


if __name__ == "__main__":
    # 建立訊息佇列
    # 3:表示訊息佇列的最大個數
    queue = multiprocessing.Queue(3)
    # 存放資料
    queue.put(1)
    queue.put("hello")
    queue.put([1, 5, 8])
    # 總結:佇列可以放入任意型別的資料
    
    # queue.put("xxx": "yyy")
    # 放入訊息的時候不會進行等待,如果發現佇列滿了不能放入資料,那麼會直接崩潰
    # 建議: 放入資料統一使用 put 方法
    # queue.put_nowait(("xxx": "yyy"))

    # 判斷佇列是否滿了
    result = queue.full()
    print(result)
    # 判斷佇列是否為空,不靠譜(加延時可解決)
    result = queue.empty()
    print("佇列是否為空:", result)

    # 獲取佇列訊息個數
    size = queue.qsize()
    print("訊息個數:", size)
    # 獲取佇列中的資料
    res = queue.get()
    print(res)
    # 如果佇列空了,那麼使用get方法會等待佇列有訊息以後再取值

訊息佇列Queue完成程式間通訊的演練

import multiprocessing
import time


# 新增資料
def add_data(queue):
    for i in range(5):
        # 判斷佇列是否滿了
        if queue.full():
            # 如果滿了跳出迴圈,不再新增資料
            print("佇列滿了")
            break
        queue.put(i)
        print("add:", i)
        time.sleep(0.1)

def read_data(queue):
    while True:

        if queue.qsize == 0:
            print("佇列空了")
            break

        result = queue.get()
        print("read:", result)


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

    # 建立新增資料的子程式
    add_process = multiprocessing.Process(target=add_data, args=(queue,))

    # 建立讀取資料的子程式
    read_process = multiprocessing.Process(target=read_data, args=(queue,))

    # 啟動程式
    add_process.start()
    # 主程式等待寫入程式執行完成以後程式碼再繼續往下執行
    add_process.join()
    read_process.start()
程式池Pool
程式池的概念

池子裡面放的是程式,程式池會根據任務執行情況自動建立程式,而且儘量少建立程式,合理利用程式池中的程式完成多工

當需要建立的子程式數量不多時,可以直接利用multiprocess中的Process動態生成多個程式,但如果是上百甚至上千個目標,手動的去建立程式的工作量巨大,此時就可以用到multiprocess模組提供的Pool方法。

初始化Pool時,可以指定一個最大程式數,當有新的請求提到Pool中時,如果池還沒有滿,那麼就會建立一個新的程式用來執行該請求,但如果池中的程式數已經達到指定的最大值,那麼該請求就會等待,直到池中有程式結束,才會用之前的程式來執行新的任務。

程式池同步執行任務

程式池同步執行任務表示程式池中的程式在執行任務的時候一個執行完成另外一個才能執行,如果沒有執行完會等待上一個程式執行

程式池同步例項程式碼

import multiprocessing
import time


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

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

複製中... 6172
複製中... 972
複製中... 972
複製中... 1624
複製中... 1624

***Repl Closed***
程式池非同步執行任務

程式池非同步執行任務表示程式池中的程式同時執行任務,程式之間不會等待

程式池非同步例項程式碼

import multiprocessing
import time


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

    # 獲取當前程式的守護狀態
    # 提示:使用程式池建立的程式時守護主程式的狀態,預設自己通過Process建立的程式是不守護主程式的狀態
    # print(multiprocessing.current_process().daemon)
    time.sleep(1)

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()
執行結果:

複製中... 1848
複製中... 12684
複製中... 12684
複製中... 6836
複製中... 6836

***Repl Closed***

個人獨立部落格:www.limiao.tech
微信公眾號:TechBoard



相關文章