Invocation of multiprocessing i Python 3.11 på Windows

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har et problem med multiprocessing i Python 3.11 på Windows.


Her er scriptet:


from multiprocessing import Process
import os
import time

def info(title):
        print(title)
        print('module name:', \_\_name\_\_)
        if hasattr(os, 'getppid'):  # only available on Unix
               print('parent process:', os.getppid())
        print('process id:', os.getpid())

def f(name):
        info('function f')
        print('--- hello', name)
        time.sleep(5)
        print('--- bye', name)

def some\_func():
        print('Running some\_func function')

def another\_func():
        print('Running another\_func function')


def main():
        print('Running main function of try\_multi.py')
        print('-------------------------------------')
        some\_func()
        if \_\_name\_\_ == '\_\_main\_\_':
               info('main line')
               p1 = Process(target=f, args=('bob',))
               p2 = Process(target=f, args=('larry',))
               p1.start()
               p2.start()
               p1.join()
               p2.join()
        another\_func()

main()


Her er det s output:


C:Scripts> c:Python31python.exe try\_multi.py
Running main function of try\_multi.py
-------------------------------------
Running some\_func function
main line
module name: \_\_main\_\_
process id: 12696
Running main function of try\_multi.py
-------------------------------------
Running some\_func function
Running another\_func function
function f
module name: \_\_main\_\_
process id: 14568
--- hello bob
Running main function of try\_multi.py
-------------------------------------
Running some\_func function
Running another\_func function
function f
module name: \_\_main\_\_
process id: 9336
--- hello larry
--- bye bob
--- bye larry
Running another\_func function


Problemet er, at jeg forventer kun, at funktionen 'f' skal køre i de nye processer, men det ser ud til, at hele den nye forekomst af overordnet scriptet er startet - både 'some\_fun' og 'another\_func' run.


På Linux med Python 2.7.5 fungerer det som forventet:


$ python try\_multi.py
Running main function of try\_multi.py
-------------------------------------
Running some\_func function
main line
('module name:', '\_\_main\_\_')
('parent process:', 1137)
('process id:', 1167)
function f
('module name:', '\_\_main\_\_')
('parent process:', 1167)
('process id:', 1168)
('--- hello', 'bob')
function f
('module name:', '\_\_main\_\_')
('parent process:', 1167)
('process id:', 1169)
('--- hello', 'larry')
('--- bye', 'bob')
('--- bye', 'larry')
Running another\_func function


Kan jeg få det til at fungere korrekt på min platform (Python 3.11 på Windows)?
tak skal du have

Bedste reference


Dette forklares i Programmeringsretningslinjer i dokumenterne: [9]



  Sørg for, at hovedmodulet kan importeres sikkert af en ny Python-tolk uden at forårsage utilsigtede bivirkninger (sådan starter en ny proces).



Generelt betyder det, at du vil ændre den sidste linje i dit script fra dette:


main()


… Til dette:


if \_\_name\_\_ == '\_\_main\_\_':
    main()


Ellers vil alle nye børneprocesser starte op og straks forsøge at ringe main og gyde to nye processer. Uanset om dette kun går dybt, eller går uendeligt dybt og forkombinerer dit system eller giver en undtagelse, afhænger af alle slags detaljer, der ikke er værd at komme ind i, men det vil aldrig gøre det rigtige ved Windows.





Hvis du undrer dig over, hvorfor det virker på Linux: I Windows fungerer multiprocessing ved at lancere en helt ny Python-tolk og få den til at importere og køre dit modul, så hele topniveaukoden i modulet bliver kørt Linux, det virker ved at forking en kopi af den aktuelle tolkproces og derefter starte opgaven derfra, så det behøver ikke at genoprette scriptet, så topnivån kodes normalt ikke igen.


I nyere versioner af Python (3.1 er virkelig gamle ...) har de renset lidt for lidt og gjort dem lidt mere fleksible, så du kan gøre gode ting som at få den samme adfærd på begge platforme ved at angive set\_start\_method('spawn')]]. Men de grundlæggende standardresultater vil være de samme.