Ich verwende python.multiprocessing.sharedctypes.RawArray
, um große Anzahl Arrays zwischen mehreren Prozessen zu teilen. Und ich habe bemerkt, dass, wenn dieses Array groß ist (> 1 oder 2 GB), es sehr langsam initialisiert wird und auch viel langsamer beim Lesen/Schreiben ist (und Lese-/Schreibzeit ist nicht vorhersehbar, manchmal ziemlich schnell, manchmal sehr sehr) langsam).Schreiben in Shared Memory in Python ist sehr langsam
Ich habe ein kleines Beispielskript erstellt, das nur einen Prozess verwendet, ein freigegebenes Array initialisiert und mehrere Male darauf schreibt. Und misst Zeit für diese Operationen.
import argparse
import ctypes
import multiprocessing as mp
import multiprocessing.sharedctypes as mpsc
import numpy as np
import time
def main():
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-c', '--block-count', type=int, default=1,
help='Number of blocks to write')
parser.add_argument('-w', '--block-width', type=int, default=20000,
help='Block width')
parser.add_argument('-d', '--block-depth', type=int, default=15000,
help='Block depth')
args = parser.parse_args()
blocks = args.block_count
blockwidth = args.block_width
depth = args.block_depth
start = time.perf_counter()
shared_array = mpsc.RawArray(ctypes.c_uint16, blocks*blockwidth*depth)
finish = time.perf_counter()
print('Init shared array of size {:.2f} Gb: {:.2f} s'.format(blocks*blockwidth*depth*ctypes.sizeof(ctypes.c_uint16)/1024/1024/1024, (finish-start)))
numpy_array = np.ctypeslib.as_array(shared_array).reshape(blocks*blockwidth, depth)
start = time.perf_counter()
for i in range(blocks):
begin = time.perf_counter()
numpy_array[i*blockwidth:(i+1)*blockwidth, :] = np.ones((blockwidth, depth), dtype=np.uint16)
end = time.perf_counter()
print('Write = %.2f s' % (end-begin))
finish = time.perf_counter()
print('Total time = %.2f s' % (finish-start))
if __name__ == '__main__':
main()
Wenn ich diesen Code ausführen ich folgende auf meinem PC erhalten:
$ python shared-minimal.py -c 1
Init shared array of size 0.56 Gb: 0.36 s
Write = 0.13 s
Total time = 0.13 s
$ python shared-minimal.py -c 2
Init shared array of size 1.12 Gb: 0.72 s
Write = 0.12 s
Write = 0.13 s
Total time = 0.25 s
$ python shared-minimal.py -c 4
Init shared array of size 2.24 Gb: 5.40 s
Write = 1.17 s
Write = 1.17 s
Write = 1.17 s
Write = 1.57 s
Total time = 5.08 s
Im letzten Fall, wenn Array-Größe mehr als 2 GB ist, ist die Initialisierung Zeit nicht linear abhängig von Array-Größe und das Zuweisen von Sicherungsgrößen-Slices zum Array ist mehr als 5-mal langsamer.
Ich frage mich, warum das passiert. Ich benutze das Skript unter Ubuntu 16.04 mit Python 3.5. Ich habe auch bemerkt, indem iotop, dass beim Initialisieren und Schreiben in das Array gibt es eine Platte schreiben Aktivität mit der gleichen Größe wie Shared Array, aber ich bin mir nicht sicher, ob eine echte Datei erstellt wird oder es ist nur im Speicherbetrieb (I angenommen, es sollte sein). Im Allgemeinen wird mein System weniger reaktionsfähig, im Falle eines großen gemeinsamen Arrays. Es wird nicht getauscht, geprüft mit top
, ipcs -mu
und vmstat
.
Verfügt Ihr System über 2 GB physischen Speicher? Es klingt, als würde es tauschen. – pvg
@pvg es hat 16 GB Speicher, und ich habe auch auf einem Computer mit 64 GB Speicher getestet. Die Ergebnisse sind nicht immer die gleichen, aber auf dem Computer mit 16 GB physischen Speicher beginnt es erheblich langsamer zu verlangsamen, wenn Shared Array mehr als ~ 1,5 GB ist, und auf der Maschine mit 64 GB Shared Array ist mehr als ~ 6,5 GB. Außerdem habe ich versucht, "top" und "ipcs -mu" auszuführen, und sie zeigen keine Änderung der Swap-Nutzung. –
Sie möchten wahrscheinlich etwas wie 'vmstat' oder irgendetwas anderes, das Sie tatsächliche Swap-Ins und Outs statt Nutzung verfolgen können. Speicherzugriffszeiten können sich aus verschiedenen Gründen nichtlinear ändern, aber es ist schwierig, den Plattenzugriff und das nicht reagierende System durch etwas anderes als das Tauschen zu erklären. – pvg