標籤:

用python多進程,fork()之後創建了新進程,原來上下文裡面的局部變數也會再創建值完全一樣的么?

使用的是multiprocessing庫,如果在業務運行當中動態的創建了若干個新的進程,但是它又不是進程池。那麼會不會每個進程中的局部變數會被歷次fork創建很多份?(這個是我比較擔心的)


是,準確來說不是每個變數都重新創建,而是整個進程的內存被複制了一份。保護模式下每個進程都有獨立的地址空間,把整個地址空間複製下來,兩個進程就一模一樣了,再處理下文件號的繼承和共享關係就可以了。雖然是完全複製,但是實現上只是把兩個分頁指向了相同的物理內存,修改時才會實際複製,所以fork並不會顯著增加內存用量。


蟹妖

linux系統裡面,fork出來的進程,其變數與源進程相同,如果只做讀取,那麼不會內存分配,如果發生寫入,那麼創建新內存頁


創建進程時的行為完全依賴於操作系統的具體實現。傳統上Linux系統的進程fork是比較輕量的,內存頁面是copy on write的。

==============

繼續補充: @依雲 對於引用計數的描述是大致正確的:整數常量在被使用時會被計數,變數在賦值到另一個變數時首先是引用的。詳情可見:python - What does CPython actually do when "=" is performed on primitive type variables?

==============

與題目沒什麼關係的補充:即使不論CoW,我暫時沒有看到Python的簡單類型進行「直接」操縱還需要修改引用計數的證據。隨便在源代碼里掃了一眼,比如,Python的int類型的基本操作:

static long
int_hash(PyIntObject *v)
{
/* XXX If this is changed, you also need to change the way
Pythons long, float and complex types are hashed. */
long x = v -&> ob_ival;
if (x == -1)
x = -2;
return x;
}

static PyObject *
int_add(PyIntObject *v, PyIntObject *w)
{
register long a, b, x;
CONVERT_TO_LONG(v, a);
CONVERT_TO_LONG(w, b);
/* casts in the line below avoid undefined behaviour on overflow */
x = (long)((unsigned long)a + b);
if ((x^a) &>= 0 || (x^b) &>= 0)
return PyInt_FromLong(x);
return PyLong_Type.tp_as_number-&>nb_add((PyObject *)v, (PyObject *)w);
}

static PyObject *
int_sub(PyIntObject *v, PyIntObject *w)
{
register long a, b, x;
CONVERT_TO_LONG(v, a);
CONVERT_TO_LONG(w, b);
/* casts in the line below avoid undefined behaviour on overflow */
x = (long)((unsigned long)a - b);
if ((x^a) &>= 0 || (x^~b) &>= 0)
return PyInt_FromLong(x);
return PyLong_Type.tp_as_number-&>nb_subtract((PyObject *)v,
(PyObject *)w);
}

而那個宏也並不會幹什麼特別的事情,除非你的類型不對:

#define CONVERT_TO_LONG(obj, lng)
if (PyInt_Check(obj)) {
lng = PyInt_AS_LONG(obj);
}
else {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}

理論上講,為了訪問數據而修改引用計數,也是非常奇怪的。引用計數代表了對於數據的一份持有權,我的訪問操作並不打算持有它,談何計數?


推薦閱讀:

10行Python代碼的詞雲
如何優雅地管理項目配置
Python如何識別二維碼
爬取豆瓣有關張國榮日記(二)—— 策略源碼知識點

TAG:Python |