問題描述
下面的代碼在windows和linux(都是python2.7)上運行時輸出不同
The following code has different output when running on windows and linux (both with python2.7)
'''import_mock.py'''
to_mock = None
'''test.py'''
import import_mock
from multiprocessing import Process
class A(object):
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def __getstate__(self):
print '__getstate__'
return { 'a': self.a, 'b': self.b,
'c':0 }
def func():
import_mock.to_mock = 1
a = A()
return a
def func1(a):
print a.a, a.b, a.c
print import_mock.to_mock
if __name__ == '__main__':
a = func()
p = Process(target=func1, args=(a,))
p.start()
p.join()
在 windows 上,輸出為:
On windows, the output is:
__getstate__
1 2 0
None
這是我的預期
在linux上是:
1 2 3
1
不克隆全局對象和傳遞的參數(shù).
Which not clone the global object and the passed args.
我的問題是為什么他們的行為不同?以及如何使 linux 代碼的行為與 windows one 相同?
My question is why they behave differently? And how to make the linux code behave the same as windows one?
推薦答案
補充@Blckknght 的回答:在 Windows 上,每個進程從頭開始"導入原始模塊,而在 Unix-y 系統(tǒng)上只有主進程運行整個模塊,而所有其他進程看到在 fork()
用于創(chuàng)建新進程時存在的任何內(nèi)容(不,你沒有調(diào)用 fork()
自己 - multiprocessing
內(nèi)部在創(chuàng)建新進程時調(diào)用它).
Adding to @Blckknght's answer: on Windows, each process imports the original module "from scratch", while on Unix-y systems only the main process runs the whole module, while all other processes see whatever exists at the time fork()
is used to create the new processes (no, you're not calling fork()
yourself - multiprocessing
internals call it whenever it creates a new process).
詳細來說,對于您的 import_mock
:
In detail, for your import_mock
:
在所有平臺上,主進程調(diào)用
func()
,將import_mock.to_mock
設置為1.
在 Unix-y 平臺上,這是所有新進程所看到的:fork()
發(fā)生在之后,因此 1 是所有新進程繼承的狀態(tài).
On Unix-y platforms, that's what all new processes see: the fork()
occurs after that, so 1 is the state all new processes inherit.
在 Windows 上,所有新進程從頭開始"運行整個模塊.所以他們每個人都導入了自己的全新版本的 import_mock
.只有主進程調(diào)用 func()
,所以只有主進程看到 to_mock
變?yōu)?1.所有其他進程看到新的 None
狀態(tài).
On Windows, all new processes run the entire module "from scratch". So they each import their own, brand new version of import_mock
. Only the main process calls func()
, so only the main process sees to_mock
change to 1. All other processes see the fresh None
state.
這一切都在意料之中,實際上很容易理解第二次;-)
That's all expected, and actually easy to understand the second time ;-)
傳遞 a
的情況更為微妙,因為它更多地取決于 multiprocessing
實現(xiàn)細節(jié).實現(xiàn)本可以從一開始就選擇在所有平臺上腌制參數(shù),但它沒有,現(xiàn)在在一些平臺上不破壞東西的情況下改變已經(jīng)太晚了.
What's going on with passing a
is subtler, because it depends more on multiprocessing
implementation details. The implementation could have chosen to pickle arguments on all platforms from the start, but it didn't, and now it's too late to change without breaking stuff on some platforms.
由于寫時復制 fork()
語義,在 Unix 上腌制 Process()
參數(shù)不是必要 -y 系統(tǒng),因此實施從未如此.但是,如果沒有 fork()
,則必須在 Windows 上腌制它們 - 實現(xiàn)也是如此.
Because of copy-on-write fork()
semantics, it wasn't necessary to pickle Process()
arguments on Unix-y systems, and so the implementation never did. However, without fork()
it is necessary to pickle them on Windows - and so the implementation does.
在允許您在所有平臺上強制Windows 實現(xiàn)"(spawn
)的 Python 3.4 之前,沒有機械方法可以避免可能的跨平臺意外.
Before Python 3.4, which allows you to force "the Windows implementation" (spawn
) on all platforms, there's no mechanical way to avoid possible cross-platform surprises.
但在實踐中,我很少對此感到困擾.知道,例如,多處理可能嚴重依賴于酸洗,我完全不知道在任何地方玩泡菜的把戲.您在傳遞 A()
實例時遇到問題"的唯一原因是您在玩泡菜技巧(通過覆蓋默認的 __getstate__()
).
But in practice, I've rarely been bothered by this. Knowing that, for example, multiprocessing can depend heavily on pickling, I stay completely clear of getting anywhere near playing tricks with pickles. The only reason you had "a problem" passing an A()
instance is that you are playing pickle tricks (via overriding the default __getstate__()
).
這篇關于為什么 multiprocessing.Process 在 windows 和 linux 上對于全局對象和函數(shù)參數(shù)的行為不同的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!