2015-11-06 9 views
5

Sto imparando la multielaborazione in python. Ho provato il multiprocessing e dopo aver letto il codice sorgente del modulo multiprocessing, ho trovato che utilizza os.fork(), quindi scrivo del codice per testare os.fok(), ma sono bloccato. Il mio codice è il seguente:Python: come funziona os.fork()?

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import os 
import time 

for i in range(2): 
    print '**********%d***********' % i 
    pid = os.fork() 
    print "Pid %d" % pid 

penso che il ciascuna stampa sarà eseguito due volte, ma hanno eseguito tre times.I non riesce a capire come questo lavoro? Ho letto questo Need to know how fork works?
Da ciò che questo articolo dice che sarà anche eseguito due volte, quindi sono così stucked ......

risposta

9

Per rispondere alla domanda direttamente, os.fork() opere chiamando la funzione di sistema operativo sottostante fork().

Ma sei sicuramente interessato a ciò che fa. Bene, questo crea un altro processo che riprenderà esattamente nello stesso punto di questo. Quindi, durante il primo ciclo, si ottiene un fork dopo il quale si hanno due processi, quello "originale" (che ottiene un valore pid del PID del processo figlio) e quello forked (che ottiene un valore pid di 0) .

Entrambi stampano il loro valore pid e proseguono con la 2a corsa del ciclo, che entrambi stampano. Poi entrambi forchetta, lasciandovi con 4 processi che stampano tutti i rispettivi valori pid. Due di loro dovrebbero essere 0, gli altri due dovrebbero essere i PID del bambino che hanno appena creato.

Modifica del codice a

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import os 
import time 

for i in range(2): 
    print '**********%d***********' % i 
    pid = os.fork() 
    if pid == 0: 
     print "%d just was created." % os.getpid() 
    else: 
     print "%d just created %d." % (os.getpid(), pid) 

si vedrà meglio cosa accade: ogni processo vi dirà il proprio PID e quello che è successo sulla forcella.

+0

hai ragione. e dovrei chiamare os._exit() nel sottoprocesso per evitare la forchetta profonda ... – tudouya

+0

@tudouya Giusto. O semplicemente rompere il ciclo. – glglgl

10

Prima di tutto, rimuovere la riga print '******...'. Semplicemente confonde tutti. Invece, proviamo questo codice ...

import os 
import time 

for i in range(2): 
    print "I'm about to be a dad!" 
    time.sleep(5) 
    pid = os.fork() 
    if pid == 0: 
     print "I'm {}, a newborn that knows to write to the terminal!".format(os.getpid()) 
    else: 
     print "I'm the dad of {}, and he knows to use the terminal!".format(pid) 
     os.waitpid(pid) 

Ok, prima di tutto, cos'è la "forcella"? La forcella è una caratteristica dei sistemi operativi moderni e conformi agli standard (ad eccezione di M $ Windows: la battuta di un sistema operativo è tutt'altro che moderna e conforme agli standard) che consente un processo (noto come "programma" e che include il Interprete Python!) Per fare letteralmente un duplicato esatto di se stesso, creando effettivamente un nuovo processo (un'altra istanza del "programma"). Una volta che la magia è terminata, entrambi i processi sono indipendenti. Cambiare qualcosa in uno di essi non ha effetto sull'altro.

Il processo responsabile della spiegazione di questo incanto oscuro e antico è noto come processo genitore. Il risultato senz'anima di questa abominazione nella vita stessa è noto come processo del bambino.

Come dovrebbe essere ovvio a tutti, compresi quelli per i quali non lo è, puoi diventare un membro di quel gruppo selezionato di programmatori che hanno venduto la loro anima per mezzo di os.fork(). Questa funzione esegue un'operazione a forcella e, di conseguenza, genera un secondo processo creato dal nulla.

Ora, cosa restituisce questa funzione o, ancora più importante, come restituisce? Se non vuoi diventare pazzo, per favore, non andare a leggere il file /kernel/fork.c del kernel Linux!Una volta che il kernel fa ciò che sappiamo deve fare, ma non vogliamo accettarlo, os.fork() restituisce in i due processi! Sì, anche lo stack di chiamate è copiato!

Quindi, se sono copie esatte, come fa una differenza tra genitore e figlio? Semplice. Se il risultato di os.fork() è zero, allora stai lavorando nel figlio. Altrimenti, stai lavorando in parent e il valore di ritorno è il PID (Process IDentifier) ​​del bambino. Ad ogni modo, il bambino può ottenere il proprio PID da os.getpid(), no?

Ora, tenendo conto di questo, e il fatto che fare fork() all'interno di un ciclo è la ricetta per il disordine, questo è ciò che accade. Chiamiamo il processo originale il processo "master" ...

  • Master: i = 0, forchette in bambino- # 1-di-master
    • Child # 1-di-master: i = 1 forchette in bambino- # 1-del-bambino- # 1-di-master
    • Child # 1-del-bambino- # 1-di-master: for ciclo su, esce
    • Child # 1-di-master : for loop over, uscite
  • Master: i = 1, forchette in bambino- # 2-di-master
    • Child # 2-di-master: i = 1 forchette in bambino- # 1-del-bambino- # 2-di-master
    • Child # 1-del-bambino- # 2-di-master: for ciclo su, esce
    • Child # 2-di-master: for ciclo su, esce
  • master: for ciclo su , uscite

Come si può vedere, ci sono un totale di 6 processi, con conseguente 6 linee di produzione, una cosa del genere ...

Sono il papà di 12120, e sa utilizzare il terminale!

Sono 12120, un neonato che sa scrivere sul terminale!

Sono il papà del 12121 e sa usare il terminale!

Sono 12121, un neonato che sa scrivere sul terminale!

Sono il papà del 12122 e sa usare il terminale!

Sono 12122, un neonato che sa scrivere sul terminale!

Ma questo è solo arbitrario, potrebbe avere in uscita questo fuori invece ...

Sono 12120, un neonato che sa scrivere sul terminale!

Sono il papà di 12120 e sa usare il terminale!

Sono 12121, un neonato che sa scrivere sul terminale!

Sono il papà del 12121 e sa usare il terminale!

Sono 12122, un neonato che sa scrivere sul terminale!

Sono il papà del 12122 e sa usare il terminale!

O altro. Il sistema operativo (e gli orologi funky della scheda madre) è l'unico responsabile dell'ordine in cui i processi ottengono tempi, quindi vai blame on Torvalds (and expect no self-steem when back) se non ti piace come il kernel gestisce l'organizzazione dei tuoi processi;).

Spero che questo abbia portato un po 'di luce su di te!

+2

Spiegazione molto bella. –