2017-02-09 11 views
3

Этот код выполняется в linux, но генерирует объект AttributeError: type «T» не имеет атрибута «val» в окнах, почему?Python multiprocessing linux windows difference

from multiprocessing import Process 
import sys 

class T(): 
    @classmethod 
    def init(cls, val): 
     cls.val = val 

def f(): 
    print(T.val) 

if __name__ == '__main__': 
    T.init(5) 

    f() 

    p = Process(target=f, args=()) 
    p.start() 

ответ

2

Windows, не хватает fork() системный вызов, который дублирует текущий процесс. Это имеет много последствий, включая те, которые перечислены на странице документации windows multiprocessing. Более конкретно:

Bear in mind that if code run in a child process tries to access a global variable, then the value it sees (if any) may not be the same as the value in the parent process at the time that Process.start was called.

В внутренностях, питон создает новый процесс на окнах, начав новый процесс с нуля, и говорят это, чтобы загрузить все модули снова. Поэтому любое изменение, которое вы сделали в текущем процессе, не будет видно.

В вашем примере это означает, что в дочернем процессе ваш модуль будет загружен, но раздел if __name__ == '__main__' не будет запущен. Поэтому T.init не будет вызываться, а T.val не будет существовать, таким образом, вы увидите ошибку.

С другой стороны, в системах POSIX (включая Linux) при создании процесса используется fork, и все глобальное состояние остается нетронутым. Ребенок работает с копией всего, поэтому ему не нужно ничего перезагружать и будет видеть свою копию T с ее копией val.

Это также означает, что процесс создания намного быстрее и намного легче при использовании ресурсов в системах POSIX, тем более что «дублирование» использует copy-on-write, чтобы избежать накладных расходов при фактическом копировании данных.

При использовании многопроцессорности существуют другие причуды, все из которых подробно описаны в python multiprocessing guidelines.

+0

'fork' vs' spawn' - очень старая дискуссия. Ядро NT всегда имело возможность делать вилку с копированием на запись, но сам API Windows, выходящий из MS-DOS, не позволяет этого. Кроме того, существуют нетривиальные проблемы с форматированием многопоточного процесса, и в этом случае Python 3.4 предоставляет вам еще два варианта запуска в дополнение к «fork»: «forkserver» и «spawn». Последний является единственным вариантом в Windows. – eryksun

+1

Это точно. Я всегда находил странный системный вызов fork, доступный в Win32, несмотря на то, что базовые функции присутствуют в ядре NT. Я не могу не видеть, что Microsoft не хочет сдаваться старым * «Те, кто не понимает Unix, обречены изобретать его». Черт, они дождались W2k8 до того, как окончательно добавили символические ссылки. Я готов поспорить, что в некоторых будущих версиях Windows будет '-эквивалент' fork() ', просто дайте им время. Возможно, с таким именем, как 'DuplicateCurrentProcess'. – spectras

+0

Что я имею в виду, не позволяя этому способ, которым система эволюционировала из Windows 2.0, работающей на DOS, просто не будет работать с 'fork' - по крайней мере, не для активного процесса. Окно в режиме ядра (win32k.sys) расширяет структуры NT 'EPROCESS' и' ETHREAD' способами, для которых 'fork', вероятно, будет проблематичным, например, блокировкой. OTOH, для анализа процесса у нас есть возможность разблокировать инертный [моментальный снимок] (https://msdn.microsoft.com/en-us/library/dn457825). – eryksun