2015-04-17 10 views
5

Diciamo che ho una discussione e la parte principale del programma. A causa di GIL, un thread dovrebbe funzionare alla volta (e non in modo simulatoso)? Ma cosa succede se uno dei thread è un ciclo infinito (o entrambi per quella materia)?Thread Python e GIL

Questi due processi verranno eseguiti in parallelo?

def test(): 
     while True: 
      print "hello" 

    def test2(): 
     while True: 
      print "hi" 

    def start_thread(): 
     try: 
      thread.start_new_thread(test2,()) 
     except: 
      print "Error: Unable to start thread" 
    start_thread() 
    test() 
+0

Non stai chiamando start_thread da nessuna parte? – ZdaR

+0

Questo codice era solo a scopo illustrativo lol Spiacente, ho appena aggiunto la riga di codice che avvia il thread –

risposta

6

Faranno eseguiti simultaneamente, ma in realtà non in parallelamente. Il sistema operativo passa frequentemente avanti e indietro tra i due thread, in modo che entrambi siano in grado di svolgere il proprio lavoro. Questo è ciò che si intende per "concurrent"; un thread non deve attendere che l'altro termini prima che possa iniziare a funzionare. Ma a causa del GIL, non funzioneranno mai entrambi nello stesso momento, in cui ognuno viene eseguito su un core diverso in parallelo. Ogni thread verrà eseguito per un po ', interromperà mentre l'altro thread viene eseguito, quindi ricomincerà a funzionare, quindi metterà in pausa, ecc.

Questo è abbastanza facile da vedere se si esegue solo il codice di esempio. Ecco l'output sulla mia macchina:

hello 
hi 
hello 
hi 
hello 
hi 
hello 
hi 
hello 
hi 
hello 
hi 
hello 
hi 
hello 
hi 
hello 
hi 

Chiaramente, entrambi i thread sono in esecuzione. Ogni thread è solo in esecuzione più lentamente di quanto sarebbe se un thread fosse in esecuzione nel programma.

Considerate questo esempio, in cui ogni filo calcola la sequenza Fibonacci:

import thread 
import time 


def fib(n): 
    if n <= 1: 
     return n 

    return fib(n-1) + fib(n-2) 

def test(): 
    while True: 
     start = time.time() 
     out = fib(32) 
     print "hello %s: %s" % (out, str(time.time() - start)) 

def test2(): 
    while True: 
     out = fib(20) 

def start_thread(): 
    try: 
     thread.start_new_thread(test2,()) 
    except: 
     print "Error: Unable to start thread" 
#start_thread() 
test() 

Con solo test esecuzione (quindi senza seconda filettatura), ottengo questo output:

hello 2178309: 0.953778982162 
hello 2178309: 0.954975128174 
hello 2178309: 0.95578789711 
hello 2178309: 0.949182033539 

Se inizio fino test2 in background, così, ottengo questo:

hello 2178309: 4.07990288734 
hello 2178309: 4.08523893356 
hello 2178309: 2.51651597023 
hello 2178309: 2.13291287422 
hello 2178309: 2.19885015488 

Come puoi vedere, le prestazioni hanno un enorme successo.

Nota che se uno dei thread sta facendo qualcosa che rilascia l'I/O di blocco simile a GIL, o chiama in una libreria C che rilascia GIL, non vedrai questo tipo di degrado delle prestazioni, perché in quello caso entrambi i thread possono effettivamente funzionare in parallelo. Questo non si applica nell'esempio precedente, poiché nessuno dei due thread sta eseguendo lavori che rilasciano GIL.

+0

Vedo ... Grazie. Quanto più lento funzionerà? È così importante? Diciamo che sto eseguendo un programma per il mercato azionario, un thread sta ricevendo dati dal broker e l'altro thread sta eseguendo ordini. La latenza dovrebbe essere il più bassa possibile (al massimo i millisecondi). Funzionerebbe ancora? –

+0

@LuisCruz Dipende un po 'da ogni thread. In due programmi con thread, in cui uno sta principalmente bloccando l'I/O e l'altro sta facendo calcoli, non dovrebbe essere * orribile * ma ci sarà qualche penalità ogni volta che arriva una richiesta. Di solito in Python si genera un processo in background usando 'multiprocessing' per gestire i calcoli, purché il sovraccarico IPC non superi il vantaggio di evitare GIL. Ma se si desidera che più thread eseguano calcoli, è assolutamente necessario utilizzare i processi. – dano

+0

Grazie mille per le informazioni. Nel mio caso un thread sta leggendo una named pipe, quindi se non ci sono dati viene bloccato. L'altro thread sta ricevendo i dati dal broker tramite un'API websocket. Quindi nel mio caso le discussioni non dovrebbero essere troppo male, suppongo. –