2014-07-27 9 views
7

ich in einigen Quellen gelesen habe, dass der Druck Befehl Thread-sicher nicht und die Abhilfe ist sys.stdout.write Befehl stattdessen zu verwenden, aber noch ist es nicht für mich arbeiten und das Schreiben in dem STDOUT ist nicht atomar.Wie kann ich eine atomare Schreibweise in Python zu stdout machen?

Hier ist ein kurzes Beispiel (genannt diese Datei parallelExperiment.py):

import os 
    import sys 
    from multiprocessing import Pool 

    def output(msg): 
    msg = '%s%s' % (msg, os.linesep) 
    sys.stdout.write(msg) 

    def func(input): 
    output(u'pid:%d got input \"%s\"' % (os.getpid(), str(input))) 

    def executeFunctionInParallel(funcName, inputsList, maxParallelism): 
     output(u'Executing function %s on input of size %d with maximum parallelism of %d' % (
      funcName.__name__, len(inputsList), maxParallelism)) 
     parallelismPool = Pool(processes=maxParallelism) 
     executeBooleanResultsList = parallelismPool.map(funcName, inputsList) 
     parallelismPool.close() 
     output(u'Function %s executed on input of size %d with maximum parallelism of %d' % (
      funcName.__name__, len(inputsList), maxParallelism)) 
     # if all parallel executions executed well - the boolean results list should all be True 
     return all(executeBooleanResultsList) 

    if __name__ == "__main__": 
    inputsList=[str(i) for i in range(20)] 
    executeFunctionInParallel(func, inputsList, 4) 

Blick auf die Ausgabe:

i. Ausgabe des Aufrufs Python parallelExperiment.py (achten, dass das Wort "pid" wird in einigen Zeilen verkorkste):

Executing function func on input of size 20 with maximum parallelism of 4 
ppid:2240 got input "0" 
id:4960 got input "2" 
pid:4716 got input "4" 
pid:4324 got input "6" 
ppid:2240 got input "1" 
id:4960 got input "3" 
pid:4716 got input "5" 
pid:4324 got input "7" 
ppid:4960 got input "8" 
id:2240 got input "10" 
pid:4716 got input "12" 
pid:4324 got input "14" 
ppid:4960 got input "9" 
id:2240 got input "11" 
pid:4716 got input "13" 
pid:4324 got input "15" 
ppid:4960 got input "16" 
id:2240 got input "18" 
ppid:2240 got input "19" 
id:4960 got input "17" 
Function func executed on input of size 20 with maximum parallelism of 4 

ii. Ausgabe von Python parallelExperiment.py> parallelExperiment.log nennen, was bedeutet, leiten Sie den stdout zum parallelExperiment.log Datei (achten Sie, dass die Reihenfolge der Zeilen ist nicht gut, weil vor und nach zu Aufruf executeFunctionInParallel dass Anrufe func parallel dazu sollte eine Meldung) gedruckt werden:

pid:3244 got input "4" 
pid:3244 got input "5" 
pid:3244 got input "12" 
pid:3244 got input "13" 
pid:240 got input "0" 
pid:240 got input "1" 
pid:240 got input "8" 
pid:240 got input "9" 
pid:240 got input "16" 
pid:240 got input "17" 
pid:1268 got input "2" 
pid:1268 got input "3" 
pid:1268 got input "10" 
pid:1268 got input "11" 
pid:1268 got input "18" 
pid:1268 got input "19" 
pid:3332 got input "6" 
pid:3332 got input "7" 
pid:3332 got input "14" 
pid:3332 got input "15" 
Executing function func on input of size 20 with maximum parallelism of 4 
Function func executed on input of size 20 with maximum parallelism of 4 
+0

Das verwirrte Ergebnis ist, was von Multi-threading erwartet wird. Sie spawnen Threads, die alle ihre eigene Zeitleiste haben. Die Tatsache, dass bash die Zeichenfolge * pid * vermasselt, ist nicht wirklich ungewöhnlich. Es ist meistens, wie Sie sagten, dass es multiple Rezeptoren nicht wirklich gut akzeptiert. Es druckt nur, was es bekommt und überlagert manchmal überlappende Rückrufe. –

Antwort

7

, dass wegen der multiprocessing.Pool passieren tatsächlich Subprozesse anstelle von Threads verwendet. Sie müssen explizite synchronization zwischen Prozessen verwenden. Beachten Sie, das Beispiel auf dem Link, es löst Ihr Problem.

import os 
import sys 
from multiprocessing import Pool, Lock 

lock = Lock() 

def output(msg): 
    msg = '%s%s' % (msg, os.linesep) 
    with lock: 
     sys.stdout.write(msg) 

def func(input): 
    output(u'pid:%d got input \"%s\"' % (os.getpid(), str(input))) 

def executeFunctionInParallel(funcName, inputsList, maxParallelism): 
    output(u'Executing function %s on input of size %d with maximum parallelism of %d' % (
     funcName.__name__, len(inputsList), maxParallelism)) 
    parallelismPool = Pool(processes=maxParallelism) 
    executeBooleanResultsList = parallelismPool.map(funcName, inputsList) 
    parallelismPool.close() 
    output(u'Function %s executed on input of size %d with maximum parallelism of %d' % (
     funcName.__name__, len(inputsList), maxParallelism)) 
    # if all parallel executions executed well - the boolean results list should all be True 
    return all(executeBooleanResultsList) 

if __name__ == "__main__": 
    inputsList=[str(i) for i in range(20)] 
    executeFunctionInParallel(func, inputsList, 4) 
+0

und kann ich die Pool.map-Methode verwenden? Das Beispiel ist für die Verwendung des "Prozess" -Objekts –

+0

Natürlich können Sie. Pool selbst verwendet Prozessobjekte intern. –

+0

Es tut mir leid, aber ich folge nicht .. Was sollte ich in ** ExecuteFunctionInParallel ** und ** Func ** Methoden ändern? –

1

Wenn Sie Verriegelung vermeiden wollen und gerne auf eine niedrigere Ebene Schnittstelle gehen, können Sie POSIX O_APPEND Verhalten mit os.open bekommen, os.write (wenn Ihr System unterstützt); und siehe Is file append atomic in UNIX?.