Skip to content

Commit 74bfb53

Browse files
authored
gh-121313: Limit the reading size from pipes to their default buffer size on POSIX systems (GH-121315)
See #121313 for analysis, but this greatly reduces memory overallocation and overhead when multiprocessing is sending non-small data over its pipes between processes.
1 parent 1ce9e58 commit 74bfb53

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

Lib/multiprocessing/connection.py

+18-3
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111

1212
import errno
1313
import io
14+
import itertools
1415
import os
16+
import stat
1517
import sys
1618
import socket
1719
import struct
18-
import time
1920
import tempfile
20-
import itertools
21+
import time
2122

2223

2324
from . import util
@@ -360,6 +361,11 @@ def _get_more_data(self, ov, maxsize):
360361
f.write(ov.getbuffer())
361362
return f
362363

364+
"""
365+
The default size of a pipe on Linux systems is 16 times the base page size:
366+
https://man7.org/linux/man-pages/man7/pipe.7.html
367+
"""
368+
PAGES_PER_PIPE = 16
363369

364370
class Connection(_ConnectionBase):
365371
"""
@@ -372,11 +378,14 @@ def _close(self, _close=_multiprocessing.closesocket):
372378
_close(self._handle)
373379
_write = _multiprocessing.send
374380
_read = _multiprocessing.recv
381+
_default_pipe_size = 0
375382
else:
376383
def _close(self, _close=os.close):
377384
_close(self._handle)
378385
_write = os.write
379386
_read = os.read
387+
_base_page_size = os.sysconf(os.sysconf_names['SC_PAGESIZE'])
388+
_default_pipe_size = _base_page_size * PAGES_PER_PIPE
380389

381390
def _send(self, buf, write=_write):
382391
remaining = len(buf)
@@ -391,8 +400,14 @@ def _recv(self, size, read=_read):
391400
buf = io.BytesIO()
392401
handle = self._handle
393402
remaining = size
403+
is_pipe = False
404+
if size > self._default_pipe_size > 0:
405+
mode = os.fstat(handle).st_mode
406+
is_pipe = stat.S_ISFIFO(mode)
407+
limit = self._default_pipe_size if is_pipe else remaining
394408
while remaining > 0:
395-
chunk = read(handle, remaining)
409+
to_read = min(limit, remaining)
410+
chunk = read(handle, to_read)
396411
n = len(chunk)
397412
if n == 0:
398413
if remaining == size:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Limit reading size in multiprocessing connection._recv for pipes to default pipe size of 16 times base page size, in order to avoid memory overallocation and unnecessary memory management system calls.

0 commit comments

Comments
 (0)