python / python/cpython

Avoid extraneous copy when `_recv`ing bytes through pipes in multiprocessing "connections"

Offen
#96,059 2 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

performance stdlib
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
36k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Feature or enhancement

Avoid extraneous copy when _recving bytes through pipes in multiprocessing "connections"

Pitch

In the default IPC implementation of the multiprocessing module using pipes, the Connection._recv method is defined as follows:

https://github.com/python/cpython/blob/586fc02be5b3e103bfddd49654034a898a8d6dfc/Lib/multiprocessing/connection.py#L378-L392

Seems like we can avoid a copy if we can read directly into a preallocated byte array? This would be beneficial if the bytes we're sending between processes are large. Another benefit here is that the buf.write() call above doesn't release the GIL, so in my workloads I've seen it causing stalls in another thread when trying to read from a multiprocessing.Queue instance.

Sample implementation that avoids the extraneous copy is shown below (bit untested). If it makes sense, I can submit a patch, but probably need some guidance to deal with the Windows case:

import io


def unix_readinto(fd, buf):
    # Thanks https://stackoverflow.com/q/13919006/1572989
    return io.FileIO(fd, closefd=False).readinto(buf)


class Connection(...):
    ...

    def _recv(self, size, readinto=unix_readinto):
        buf = io.BytesIO(initial_bytes=bytes(size))
        handle = self._handle
    
        mem = buf.getbuffer()
        total = 0
        while total != size:
            n = readinto(handle, mem[total:])
    
            if n == 0:
                if total == 0:
                    raise EOFError
                else:
                    raise OSError("got end of file during message")
    
            total += n
    
        return buf

Previous discussion

N/A

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit _recv in Lib/multiprocessing/connection.py, das im Issue verlinkt ist, und vergleiche, wie das Lesen aus Pipes unter Unix und Windows behandelt wird. Überprüfe, ob ein vorab allokierter Puffer große Nachrichten ohne die zusätzliche Kopie empfangen kann und dabei das bestehende Verhalten bei EOF und Teil-Lesevorgängen auf beiden Plattformen erhalten bleibt; das Issue nennt keine spezifischen Tests.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
distributed-systems, operating-systems
Issue-Typ
Feature
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.