python多進程

python多進程

進程簡介

進程是程序在計算機上的一次執行活動。當你運行一個程序,你就啓動了一個進程。顯然,程序是死的(靜態的),進程是活的(動態的)。進程能夠分爲系統進程和用戶進程。凡是用於完成操做系統的各類功能的進程就是系統進程,它們就是處於運行狀態下的操做系統自己;用戶進程就沒必要我多講了吧,全部由你啓動的進程都是用戶進程。進程是操做系統進行資源分配的單位。
在操做系統的管理下,全部正在運行的進程輪流使用CPU,每一個進程容許佔用CPU的時間很是短(好比10毫秒),這樣用戶根本感受不出來CPU是在輪流爲多個進程服務,就好象全部的進程都在不間斷地運行同樣。但實際上在任何一個時間內有且僅有一個進程佔有CPU。html

進程和線程

進程(process)和線程(thread)
單個CPU一次只能運行一個任務;在任一時刻,CPU老是運行一個進程,其餘進程處於非運行狀態;
一個進程能夠包含多個線程;
進程沒有任何共享狀態,進程修改的數據,改動僅限於該進程內;
一個進程的內存空間是共享的,每一個線程均可以使用這些共享內存;
一個線程使用某些共享內存時,其餘線程必須等它結束才能使用這一塊內存;防止多個線程同時讀寫某一塊內存區域,採用互斥鎖(Mutual exclusion,縮寫Mutex);
某些內存區域只能供給固定數目的線程使用,此時經過信號量(Semaphore)保證多個線程不會互相沖突;
多進程形式,運行多個任務同時運行;多線程形式,容許單個任務分紅不一樣的部分運行;
多線程使用的是cpu的一個核,適合io密集型;
多進程使用的是cpu的多個核,適合運算密集型。
在linux中可使用ps -efL查看進程和線程ID。以memcached進程爲例,輸出結果以下python

1
2
3
4
5
6
7
8
9
10
11
12
[root@VM_0_4_centos ~]# ps -efL |grep memcached
root     24421     1 24421  0   10 May19 ?        00:00:03 memcached -d -u root
root     24421     1 24422  0   10 May19 ?        00:00:01 memcached -d -u root
root     24421     1 24423  0   10 May19 ?        00:00:00 memcached -d -u root
root     24421     1 24424  0   10 May19 ?        00:00:00 memcached -d -u root
root     24421     1 24425  0   10 May19 ?        00:00:00 memcached -d -u root
root     24421     1 24426  0   10 May19 ?        00:00:00 memcached -d -u root
root     24421     1 24427  0   10 May19 ?        00:00:00 memcached -d -u root
root     24421     1 24428  0   10 May19 ?        00:00:00 memcached -d -u root
root     24421     1 24429  0   10 May19 ?        00:00:09 memcached -d -u root
root     24421     1 24430  0   10 May19 ?        00:00:00 memcached -d -u root
root     32169 31101 32169  0    1 23:23 pts/0    00:00:00 grep --color=auto memcached

 

第一行UID(用戶ID),第二行爲PID(進程ID),第三行PPID(父進程ID),第四行LWP(線程ID)。
從示例能夠看出,進程24421子進程有10個,對應線程ID分別爲24421-24430。linux

multiprocess

python中的多線程沒法利用多核優點,若要充分使用多核CPU資源,在python中大部分狀況使用多進程。python提供了很是好用的多進程包multiprocessing。
multiprocessing模塊用來開啓子進程,並在子進程中執行咱們定製的任務(好比函數),該模塊與多線程模塊threading的編程接口相似。
multiprocessing模塊的功能衆多:支持子進程、通訊和共享數據、執行不一樣形式的同步,提供了Process、Queue、Pipe、Lock等組件。編程

Process類

建立一個Process對象centos

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

 

  • 參數
    target:函數名字
    args:函數須要的參數,以tuple的形式傳入(單個元素的tuple必須有逗號)安全

  • 方法
    p.is_alive() 判斷進程p是否存活,是返回True
    p.run() 啓動進程,它去調用target指定的函數
    p.start() 啓動進程,它會自動調用run方法,推薦使用start
    p.join(timeout) 主線程等待p終止(主線程處於等的狀態,p處於運行狀態)。p.join只能join使用start開啓的進程,不能join使用run開啓的進程
    p.terminate() 強制進程p退出,不會進行任何清理操做,若是p建立了子進程,該子進程就變成了殭屍進程多線程

  • 屬性
    p.name 進程的名字
    p.pid 進程的pid
    p.daemon 默認爲False,若是設置爲True表明p爲後臺運行的守護進程,當p的父進程終止時p也隨之終止,而且設置爲True後,p不能建立本身的新進程,必須在p.start()以前設置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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()

輸出結果memcached

1
2
3
4
5
6
7
8
start main
end main
start worker 1
start worker 2
start worker 3
end worker 1
end worker 2
end worker 3

 

multprocessing用到的兩個方法
cpu_count():統計cpu總數
active_children():得到全部子進程函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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)    #此處保證了p1優先執行
    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()

 

輸出結果ui

1
2
3
4
5
6
7
8
9
10
11
12
start main
start worker 1
the number of CPU is: 4
The name of active children is: Process-1, pid is: 25360 is alive
The name of active children is: Process-2, pid is: 24500 is alive
The name of active children is: Process-3, pid is: 26100 is alive
end main
start worker 3
start worker 2
end worker 1
end worker 2
end worker 3

 

lock組件

當咱們用多進程來讀寫文件的時候,若是一個進程是寫文件,一個進程是讀文件,若是兩個文件同時進行,確定是不行的,必須是文件寫結束之後,才能夠進行讀操做。或者是多個進程在共享一些資源的時候,同時只能有一個進程進行訪問,那就要有一個鎖機制進行控制。
下面使用2個進程分別進行+1+3操做爲例

  • 不加鎖
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import time
    import multiprocessing
    
    def add(value, number):
        print("start add{0} number= {1}".format(value, number))
        for i in range(1, 3):
            number += value
            time.sleep(0.3)
            print("number = {0}".format(number))
    
    
    if __name__ == '__main__':
        print("start main")
        number = 0
        p1 = multiprocessing.Process(target=add, args=(1, number))
        p3 = multiprocessing.Process(target=add, args=(3, number))
        p1.start()
        p3.start()
        print("end main")

輸出結果

1
2
3
4
5
6
7
8
start main
end main
start add1 number= 0
start add3 number= 0
number = 1
number = 3
number = 2
number = 6

 

  • 加鎖
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import time
    import multiprocessing
    
    def add(lock, value, number):
        with lock:
            print("start add{0} number= {1}".format(value, number))
            for i in range(1, 3):
                number += value
                time.sleep(0.3)
                print("number = {0}".format(number))
    
    
    if __name__ == '__main__':
        print("start main")
        number = 0
        lock = multiprocessing.Lock()
        p1 = multiprocessing.Process(target=add, args=(lock, 1, number))
        p3 = multiprocessing.Process(target=add, args=(lock, 3, number))
        p1.start()
        p3.start()
        print("end main")

輸出結果

1
2
3
4
5
6
7
8
start main
end main
start add1 number= 0
number = 1
number = 2
start add3 number= 0
number = 3
number = 6

 

鎖的獲取可使用lock.acquire()獲取,lock.release()釋放

1
2
3
4
5
6
7
8
9
10
11
12
13
def add(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

 

共享內存

通常變量在進程之間是無法進行通信的,可是multiprocessing提供了ValueArray模塊,能夠在不一樣的進程中使用同一變量。ValueArray結構內部都實現了鎖機制,所以多進程是安全的。
Value和Array都須要設置其中存放值的類型,d是double類型,i是int類型。類型設置和array模塊的值相似,更多的類型能夠點擊array — Efficient arrays of numeric values查看。
上面的示例中,兩個進程執行後number結果分別爲2和6,假如兩個進程能夠共享變量,name輸出結果將會是8。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import multiprocessing
from multiprocessing import Value

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


if __name__ == '__main__':
    print("start main")
    number = Value('d', 0)    #使用Value建立變量
    p1 = multiprocessing.Process(target=add, args=(1, number))
    p3 = multiprocessing.Process(target=add, args=(3, number))
    p1.start()
    p3.start()
    print("end main")

 

輸出結果

1
2
3
4
5
6
7
8
start main
end main
start add1 number= 0.0
start add3 number= 0.0
number = 1.0
number = 4.0
number = 5.0
number = 8.0

 

number最終結果是8,可是具體輸出結果每次執行可能存在差別。

更多關於multiprocessing的內容能夠點擊multiprocessing — Process-based parallelism查看官方介紹。

Share

相關文章
相關標籤/搜索