1. 程式人生 > >python多進程(一)

python多進程(一)

live() 支持 允許 註意 try inux 普通 服務 ldr

操作系統進程


Unix/Linux操作系統提供了一個fork()系統調用,它非常特殊。普通的函數調用,調用一次,返回一次,但是fork()調用一次,返回兩次,因為操作系統自動把當前進程(稱為父進程)復制了一份(稱為子進程),然後,分別在父進程和子進程內返回。子進程永遠返回0,而父進程返回子進程的ID。這樣做的理由是,一個父進程可以fork出很多子進程,所以,父進程要記下每個子進程的ID,而子進程只需要調用getppid()就可以拿到父進程的ID。
進程是程序在計算機上的一次執行活動。當你運行一個程序,你就啟動了一個進程。顯然,程序是死的(靜態的),進程是活的(動態的)。進程可以分為系統進程和用戶進程。凡是用於完成操作系統的各種功能的進程就是系統進程,它們就是處於運行狀態下的操作系統本身。所有由你啟動的進程都是用戶進程。
通俗地講,在操作系統的管理下,所有正在運行的進程輪流使用CPU,每個進程允許占用CPU的時間非常短(比如10毫秒),這樣用戶根本感覺不出來CPU是在輪流為多個進程服務,就好象所有的進程都在不間斷地運行一樣。但實際上在任何一個時間內有且僅有一個進程占有CPU。

多進程


多進程和多線程的區別
多線程使用的是cpu的一個核,適合io密集型。
多進程使用的是cpu的多個核,適合運算密集型。

Multiprocessing支持子進程,通信,共享數據,執行不同形式的同步,提供了Process,Pipe, Lock等組件。

Process

創建一個Process對象

p = multiprocessing.Process(target=worker_1, args=(2, ))

target = 函數名字
args = 函數需要的參數,以tuple的形式傳入
註意: 單個元素的tuple的表現形式(元素,)有一個逗號

multprocessing用到的兩個方法
cpu_count() 統計cpu總數
active_children() 獲得所有子進程

Process的對象常用方法

is_alive() 判斷進程是否存活
run() 啟動進程
start() 啟動進程,會自動調用run方法,這個常用
join(timeout) 等待進程結束或者直到超時

Process的常用屬性

name 進程名字
pid 進程的pid

相關代碼示例

import multiprocessing

import time


def worker(args, interval):
    print("start worker {0}".format(args))
    time.sleep(interval)
    
print("end worker {0}".format(args)) def main(): print("start main") p1 = multiprocessing.Process(target=worker, args=(1, 1)) p2 = multiprocessing.Process(target=worker, args=(2, 2)) p3 = multiprocessing.Process(target=worker, args=(3, 3)) p1.start() p2.start() p3.start() print("end main") if __name__ == __main__: main() 結果: start main end main start worker 1 start worker 3 start worker 2 end worker 1 end worker 2 end worker 3

p = multiprocessing.Process(target=, args=)
target 指定的是當進程執行時,需要執行的函數
args 是當進程執行時,需要給函數傳入的參數
註意: args必須是一個tuple, 特別是當函數需要傳入一個參數時 (1,)
p 代表的是一個多進程
p.is_alive() 判斷進程是否存活
p.run() 啟動進程
p.start() 啟動進程,他會自動調用run方法,推薦使用start
p.join(timeout) 等待子進程結束或者到超時時間後再繼續往下執行
p.terminate() 強制子進程退出
p.name 進程的名字
p.pid 進程的pid

import multiprocessing

import time


def worker(args, interval):
    print("start worker {0}".format(args))
    time.sleep(interval)
    print("end worker {0}".format(args))

def main():
    print("start main")
    p1 = multiprocessing.Process(target=worker, args=(1, 1))
    p2 = multiprocessing.Process(target=worker, args=(2, 2))
    p3 = multiprocessing.Process(target=worker, args=(3, 3))
    p1.start()
    p1.join(timeout=0.5)
    p2.start()
    p3.start()
    print("the number of CPU is: {0}".format(multiprocessing.cpu_count()))
    for p in multiprocessing.active_children():
       print("The name of active children is: {0}, pid is: {1} is alive".format(p.name, p.pid))
    print("end main")

if __name__ == __main__:
    main()

結果:
start main
start worker 1
the number of CPU is: 4
The name of active children is: Process-3, pid is: 9056 is alive
The name of active children is: Process-2, pid is: 5844 is alive
The name of active children is: Process-1, pid is: 8428 is alive
end main
start worker 2
start worker 3
end worker 1
end worker 2
end worker 3

創建子進程時,只需要傳入一個執行函數和函數的參數,創建一個Process實例,用start()方法啟動,這樣創建進程比fork()還要簡單。

Lock組件


當我們用多進程來讀寫文件的時候,如果一個進程是寫文件,一個進程是讀文件,如果兩個文件同時進行,肯定是不行的,必須是文件寫結束以後,才可以進行讀操作。或者是多個進程在共享一些資源的時候,同時只能有一個進程進行訪問,那就要有一個鎖機制進行控制。

當多個進程需要訪問共享資源的時候,Lock可以用來避免訪問的沖突。主要用到了lock.acquire() 和lock.release()

import time

import multiprocessing


def add1(lock, value, number):
    with lock:
        print("start add1 number= {0}".format(number))
        for i in range(1, 5):
            number += value
            time.sleep(0.3)
            print("number = {0}".format(number))

def add3(lock, value, number):
    lock.acquire()
    print("start add3 number= {0}".format(number))
    try:
        for i in range(1, 5):
            number += value
            time.sleep(0.3)
            print("number = {0}".format(number))
    except Exception as e:
        raise e
    finally:
        lock.release()
        pass

if __name__ == __main__:
    print("start main")
    number = 0
    lock = multiprocessing.Lock()
    p1 = multiprocessing.Process(target=add1, args=(lock, 1, number))
    p3 = multiprocessing.Process(target=add3, args=(lock, 3, number))
    p1.start()
    p3.start()
    print("end main")

結果:
start main
end main
start add3 number= 0
number = 3
number = 6
number = 9
number = 12
start add1 number= 0
number = 1
number = 2
number = 3
number = 4

共享內存


python的multiprocessing模塊也給我們提供了共享內存的操作。
一般的變量在進程之間是沒法進行通訊的,multiprocessing給我們提供了Value和Array模塊,他們可以在不通的進程中共同使用,Value 和 Array 都需要設置其中存放值的類型,d 是 double 類型,i 是 int 類型。

import time

import multiprocessing

from multiprocessing import Value, Array, Manager


def add1(value, number):
    print("start add1 number= {0}".format(number.value))
    for i in range(1, 5):
        number.value += value
        print("number = {0}".format(number.value))

def add3(value, number):
    print("start add3 number= {0}".format(number.value))
    try:
        for i in range(1, 5):
            number.value += value
            print("number = {0}".format(number.value))
    except Exception as e:
        raise e

if __name__ == __main__:
    print("start main")
    number = Value(d, 0)
    p1 = multiprocessing.Process(target=add1, args=(1, number))
    p3 = multiprocessing.Process(target=add3, args=(3, number))
    p1.start()
    p3.start()
    print("end main")

結果:
start main
end main
start add1 number= 0.0
number = 1.0
number = 2.0
number = 3.0
number = 4.0
start add3 number= 4.0
number = 7.0
number = 10.0
number = 13.0
number = 16.0

python多進程(一)