在代碼優化的過程中,碰到了這樣一個問題:一個進程中我定義了幾個全局變量,然后我又Process了幾個子進程,子進程中是否可以各自對全局變量進行修改?最后全局變量會取哪個值呢?
經過一番嘗試以后得到結果:
子進程繼承父進程的全局變量,而且是以復制的形式完成,所以子進程修改后的全局變量只對自己和自己的子進程有影響。
父子進程不共享這些全局變量,也就是說:父進程中對全局變量的修改不影響子進程中的全局變量,同理,子進程也不影響父進程的。
為了實現父子進程的通信,在網上經過了一番翻找以后,找到了 Value和Array 方法
Value函數返回一個shared memory包裝類,其中包含一個ctypes對象
一般 整數用 i, 字符用 c,浮點數用 d 就可以了
Array函數返回一個shared memory包裝類,其中包含一個數組,字符串需要用 Array 來傳遞
- @args shared memory 中包含的值
- @lock 默認值是True:創建一個新的lock來控制對value的訪問。該參數也可以是 multiprocessing.Lock 或 multiprocessing.RLock 對像,用來控制對value的訪問
================================================================================================================================
案例一:
def worker(num, mystr, arr): num.value *= 2 mystr.value = "ok" for i in range(len(arr)): arr[i] = arr[i] * (-1) + 1.5 def dump_vars(num, mystr, arr): print 'num: ', num.value print 'str: ', mystr[:] print 'arr: ', arr[:] if __name__=='__main__': num = Value('i', 5) mystr = Array('c', 'just for test') arr = Array('d', [1.0, 1.5, -2.0]) dir(str) print 'init value' dump_vars(num, mystr, arr) ps = [Process(target=worker, args=(num, mystr, arr)) for x in range(3)] for p in ps: p.start() for p in ps: p.join() print print 'after all workers finished' dump_vars(num, mystr, arr)
#結果: init value num: 5 str: just for test arr: [1.0, 1.5, -2.0] after all workers finished num: 40 str: ok
多次測試我發現,在共享字符串的時候,在主進程中的初始化決定了這個字符串的長度,
創建后字符串的長度固定不變,相當於把這個字符串所在的地址復制給一個指針,並且在字符串的首地址記錄了自身的長度,
在以后讀取這個值的時候就會去讀取那一段固定長度的內容,而不管現在的新內容長度是多少,舉個例子:
比如我們在主進程初始化一段字符串 "abcde",一旦初始化,長度就固定了,現在長度是5,然后我們在其他進程賦值,我們嘗試賦值為
"abcdefg",此時執行會報錯,因為長度超標了,我們在賦值為 "yes",最后輸出結果為 "yes&efg"(此處的&是代表一個不可顯示的字符,不同的環境下顯示不同,有可能顯示空格,有可能顯示null)。也就是說長短都不行,必須和初始化字符串等長。
於是得出這樣一個結論,如果你要共享一個字符串,那么在子進程中賦值時必須賦值長度相當的字符串。建議在子進程中可以先檢查字符串長度,然后在根據需要拼接指定長度的字符串
案例二:
from multiprocessing import Process, Value, Array def f(n, a): n.value = n.value + 1 for i in range(len(a)): a[i] = a[i] * 10 if __name__ == '__main__': num = Value('i', 1) arr = Array('i', range(10)) p = Process(target=f, args=(num, arr)) p.start() p.join() print(num.value) print(arr[:]) p2 = Process(target=f, args=(num, arr)) p2.start() p2.join() print(num.value) print(arr[:]) # the output is : # 2 # [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] # 3 # [0, 100, 200, 300, 400, 500, 600, 700, 800, 900]