個人Python成長之路---第八天---Python基礎(25)---2016年3月5日(晴)

多進程 multiprocessing模塊

multiprocessing模塊提供了一個Process類來表明一個進程對象python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python3
# coding:utf-8
'''
Created on: 2016年3月5日
 
@author: 張曉宇
 
Email: 61411916@qq.com
 
Version: 1.0
 
Description: 多進程演示程序
 
Help:
'''
from multiprocessing import Process
import os
 
 
def run_proc(name):
     # 子進程要執行的函數
     print ( 'Run child process %s (%s)...' % (name, os.getpid())) # os.getpid()表示得到當前進程的pid
 
if __name__ = = '__main__' :
     print ( 'Parent process %s.' % os.getpid()) # 打印父進程的pid
     p = Process(target = run_proc, args = ( 'test' ,)) # 建立進程對象,參數結構和多線程同樣
     print ( 'Child process will start.' )
     p.start() # 啓動子進程
     p.join() # 阻塞等待子進程執行完畢
     print ( 'Child process end.' )

進程間通訊

Queue

不一樣進程間內存是不共享,因此多進程不能像多線程同樣經過全局變量(固然全局變量也是不提倡的),因此只能經過隊列,多進程模塊也自帶一個隊列Queue,使用方法和threading裏的queue差很少windows

Pipe

管道,能夠理解爲兩個進程之間的一個橋樑多線程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python3
# coding:utf-8
'''
Created on: 2016年3月5日
 
@author: 張曉宇
 
Email: 61411916@qq.com
 
Version: 1.0
 
Description: 管道演示程序
 
Help:
'''
from multiprocessing import Process, Pipe
 
def f(conn):
     conn.send([ 42 , None , 'hello' ]) # 網管道里傳遞數據
     conn.close()
 
if __name__ = = '__main__' :
     parent_conn, child_conn = Pipe() # 一個是父進程的管道對象,一個是子進程的對象,本身成往裏面send,父進程對象recv,有點像socket
     p = Process(target = f, args = (child_conn,)) # 把管道對象做爲參數傳遞給子進程
     p.start()
     print (parent_conn.recv())   # 接收管道里的數據並打印出來
     p.join()

執行結果app

1
[ 42 , None , 'hello' ]

有人會說既然能夠往子進程要執行的而函數傳遞參數,直接經過這個參數取子進程傳遞過來的數據就行了,好比能夠用列表等可變數據類型(字符串和數值型等不可變類型的數據,想都不要想,統一進程都作不到)爲啥還用管道或隊列異步

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python3
# coding:utf-8
'''
Created on: 2016年3月5日
 
@author: 張曉宇
 
Email: 61411916@qq.com
 
Version: 1.0
 
Description: 管道演示程序
 
Help:
'''
from multiprocessing import Process, Pipe
 
def f(conn, strinfo):
     conn.send([ 42 , None , 'hello' ]) # 網管道里傳遞數據
     conn.close() # 關閉管道
     strinfo.append( 'child' )
 
if __name__ = = '__main__' :
     parent_conn, child_conn = Pipe() # 一個是父進程的管道對象,一個是子進程的對象,本身成往裏面send,父進程對象recv,有點像socket
     strinfo = [ 'parent' ]
     p = Process(target = f, args = (child_conn, strinfo)) # 把管道對象做爲參數傳遞給子進程
     p.start()
     print (parent_conn.recv())   # 接收管道里的數據並打印出來
     print (strinfo)
     p.join()

執行結果socket

1
2
[ 42 , None , 'hello' ]
['parent']

從執行結果中能夠看出來,strinfo的值並無變化,那是由於,進程啓動的時候從新劃分了內存空間,等於將strinfo在子進程中copy了一份,已經和父進程中的strinfo沒有半毛錢關係了因此要有管道隊列等async

進程池

進程池內部維護一個進程序列,當使用時,則去進程池中獲取一個進程, 若是進程池序列沒有可提供的進程,那麼就會等待,知道有可用進程爲止函數

Pool模塊有兩種經常使用的啓動進程的方法spa

apply和apply_assync,從字面上理解是apply_assync是異步的,其實就是apply_assync支持把一個函數做爲參數傳遞進去,當進程函數執行完的時候能夠經過return一個值,這個值,會自動做爲參數傳遞個傳遞進來的函數,並執行該函數,咱們稱之爲回調(callback)線程

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env python
# coding:utf-8
'''
Created on: 2016年3月5日
 
@author: 張曉宇
 
Email: 61411916@qq.com
 
Version: 1.0
 
Description: 進程池演示程序
 
Help:
'''
from  multiprocessing import Pool, freeze_support
import time
 
def Foo(i):
     '''
     子進程執行的函數
     :param i:
     :return:
     '''
     time.sleep( 2 )
     return i + 100
 
def Bar(arg):
     '''
     子進程回調函數
     :param arg:
     :return:
     '''
     print ( '-->exec done:' ,arg)
 
if __name__ = = '__main__' : # 這個在windows環境中絕對不能省略不然會報錯
     freeze_support()
     pool = Pool( 5 ) # 建立進程池對象
 
     for i in range ( 10 ):
         pool.apply_async(func = Foo, args = (i,), callback = Bar)
         # pool.apply(func=Foo, args=(i,))
     print ( 'end' )
     pool.close()
     pool.join() #進程池中進程執行完畢後再關閉,若是註釋,那麼程序直接關閉。

執行結果

1
2
3
4
5
6
7
8
9
10
11
end
- - > exec done: 100
- - > exec done: 101
- - > exec done: 102
- - > exec done: 103
- - > exec done: 104
- - > exec done: 105
- - > exec done: 106
- - > exec done: 107
- - > exec done: 108
- - > exec done: 109
相關文章
相關標籤/搜索