Gemeinsamer Speicher zwischen Python-Prozessen

Lesezeit: 5 Minuten

Ich versuche, einen Weg zu finden, Speicher zwischen Python-Prozessen zu teilen. Grundsätzlich gibt es Objekte, die mehrere Python-Prozesse lesen (nur lesen) und verwenden können müssen (keine Mutation). Im Moment wird dies mit redis + strings + cPickle implementiert, aber cPickle nimmt wertvolle CPU-Zeit in Anspruch, daher möchte ich das nicht verwenden müssen. Die meisten der Python-Shared-Memory-Implementierungen, die ich im Internet gesehen habe, scheinen Dateien und Gurken zu erfordern, was im Grunde das ist, was ich bereits tue und genau das, was ich versuche zu vermeiden.

Was ich mich frage, ist, ob es eine Möglichkeit gäbe, ein Like zu schreiben … im Grunde eine In-Memory-Python-Objektdatenbank/-server und ein entsprechendes C-Modul als Schnittstelle zur Datenbank?

Grundsätzlich würde das C-Modul den Server nach einer Adresse fragen, an die ein Objekt geschrieben werden soll, der Server würde mit einer Adresse antworten, dann würde das Modul das Objekt schreiben und den Server benachrichtigen, dass ein Objekt mit einem bestimmten Schlüssel auf die Festplatte geschrieben wurde angegebenen Ort. Wenn dann einer der Prozesse ein Objekt mit einem bestimmten Schlüssel abrufen wollte, fragte er einfach die Datenbank nach dem Speicherort für den angegebenen Schlüssel, der Server antwortete mit dem Ort und das Modul würde wissen, wie dieser Speicherplatz in den Speicher geladen werden soll und Übertragen Sie das Python-Objekt zurück an den Python-Prozess.

Ist das völlig unvernünftig oder nur verdammt schwer umzusetzen? Jage ich etwas Unmögliches hinterher? Irgendwelche Vorschläge wären willkommen. Danke Internet.

  • Wie wertvoll ist Ihre CPU-Zeit genau, dass es sich lohnt, eine funktionierende Lösung zu verwenden, die viel weniger fummelig zu synchronisieren ist als das, was Sie vorschlagen? Das, worum Sie bitten, kann getan werden, aber es wird eine große Qual sein, dies zu tun korrekt.

    – Millielch

    2. Juli 2012 um 23:50 Uhr


  • CPU-Zeit ist die wertvollste. Grundsätzlich kann das Entpicken von Objekten zwischen 20 ms (für ein kleines) und 60 ms (für ein großes) dauern. Ich persönlich finde beide Zeiten zu lang. EDIT: Zu lang in dem Sinne, dass es einen besseren Weg geben muss, nicht dass ich denke, dass cPickle sich nicht genug Mühe gibt.

    – Spitzname

    3. Juli 2012 um 0:29 Uhr


  • Die gemeinsame Nutzung von Speicher wäre machbar, aber die gemeinsame Nutzung von Objekten wird ernsthaft schwierig sein … Eine verwandte Frage finden Sie hier: stackoverflow.com/questions/1268252/… (es gibt einen netten Bericht von Alex Martelli, der erklärt, warum dies schwierig ist).

    – Christoph D

    3. Juli 2012 um 6:02 Uhr

  • @f34r Ist das Beizen bekanntermaßen der primäre oder zumindest ein erheblicher Engpass in Ihrer aktuellen Codebasis? Wenn nicht, ist Ihre CPU-Zeit tatsächlich reichlich vorhanden. Möglicherweise können Sie Redis ausgeben, wenn Ihre Daten nicht wirklich persistent sind, und sie durch das direkte Senden von eingelegten Werten ersetzen. Aber mein Bauchgefühl ist, dass es ohne serialisierte Nachrichten keine verteilte „Share-Nothing“-Architektur geben kann, und sie sind viel einfacher zu begründen als Shared-Memory-Systeme.

    – Millielch

    3. Juli 2012 um 9:48 Uhr


  • Ich nehme an, Sie könnten auch in die hineinschauen Sharing-Mechanismen der multiprocessing Modul. (Der erste Satz dieses Absatzes rät natürlich davon ab.)

    – Millielch

    3. Juli 2012 um 9:54 Uhr

Ab Python 3.8 und höher können Sie verwenden multiprocessing.shared_memory.SharedMemory

Nicht unvernünftig.

IPC kann mit einer speicherabgebildeten Datei durchgeführt werden. Python hat eine eingebaute Funktionalität:

http://docs.python.org/library/mmap.html

Mappen Sie einfach die Datei in beiden Prozessen und schwupps, Sie haben eine freigegebene Datei. Natürlich müssen Sie es in beiden Prozessen abfragen, um zu sehen, was sich ändert. Und Sie müssen zwischen beiden zusammenarbeiten. Und entscheiden Sie, in welches Format Sie Ihre Daten einfügen möchten. Aber es ist eine gängige Lösung für Ihr Problem.

  • Aber das würde immer noch eine Serialisierung in Bytes erfordern, ja? Der OP sagte, er versuche, das zu vermeiden.

    – Ned Batchelder

    2. Juli 2012 um 23:49 Uhr

  • Das wäre eine Art Serialisierung, ja. Vielleicht würde eine benutzerdefinierte Serialisierung besser funktionieren, wenn der Objekttyp bekannt ist. Fügen Sie alternativ einen Hashcode hinzu, um zu vermeiden, dass ein Objekt zweimal erneut deserialisiert wird. Unabhängig davon ist jedoch eine Serialisierung erforderlich.

    – Jo

    2. Juli 2012 um 23:54 Uhr

  • Bist du dir sicher? Netzwerk + Redis wäre vergleichsweise teuer. Warum nicht profilieren?

    – Jo

    3. Juli 2012 um 0:28 Uhr

  • Redis wird auf dem Computer ausgeführt, es ist kein Netzwerk-Redis-Server

    – Spitzname

    3. Juli 2012 um 1:04 Uhr

  • Trotzdem machen Sie es entweder über einen Domänen-Socket oder einen lokalen TCP-Socket, richtig?

    – Jo

    3. Juli 2012 um 6:11 Uhr

Wenn Sie kein Beizen möchten, multiprocessing.sharedctypes könnte passen. Es ist jedoch ein bisschen niedrig; Sie erhalten einzelne Werte oder Arrays bestimmter Typen.

Eine andere Möglichkeit, Daten an untergeordnete Prozesse (in eine Richtung) zu verteilen, ist multiprocessing.Pipe. Das kann mit Python-Objekten umgehen und ist in C implementiert, daher kann ich Ihnen nicht sagen, ob es Pickling verwendet oder nicht.

Benutzeravatar von Yin
Yin

Python unterstützt keinen gemeinsam genutzten Speicher zwischen unabhängigen Prozessen. Sie können Ihre eigene in C-Sprache implementieren oder verwenden SharedArray
wenn Sie mit libsvm arbeiten, numpy.ndarray, scipy.sparse.

pip install SharedArray
def test ():
    def generateArray ():
        print('generating')
        from time import sleep
        sleep(3)
        return np.ones(1000)
    a = Sarr('test/1', generateArray)

    # use same memory as a, also work in a new process
    b = Sarr('test/1', generateArray) 
    c = Sarr('test/1', generateArray)

import re
import SharedArray
import numpy as np

class Sarr (np.ndarray):
    def __new__ (self, name, getData):
        if not callable(getData) and getData is None:
            return None
        self.orig_name = name
        shm_name="shm://" + re.sub(r'[./]', '_', name)
        try:
            shm = SharedArray.attach(shm_name)
            print('[done] reuse shared memory:', name)
            return shm
        except Exception as err:
            self._unlink(shm_name)
            data = getData() if callable(getData) else getData
            shm = SharedArray.create(shm_name, data.size)
            shm[:] = data[:]
            print('[done] loaded data to shared memory:', name)
            return shm

    def _unlink (name):
        try:
            SharedArray.delete(name[len('shm://'):])
            print('deleted shared memory:', name)
        except:
            pass


if __name__ == '__main__':
    test()

1432320cookie-checkGemeinsamer Speicher zwischen Python-Prozessen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy