← Назад к вопросам
Как работает взаимодействие между процессами в Linux?
3.0 Senior🔥 131 комментариев
#DevOps и инфраструктура#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Взаимодействие между процессами (IPC) в Linux
IPC (Inter-Process Communication) — это механизм обмена данными между процессами в Linux. Существует несколько основных методов, каждый со своими преимуществами.
1. Pipes (конвейеры) — простое одностороннее взаимодействие
Пиpe — это буфер в ядре для передачи данных между процессами.
Безымянный pipe (unnamed pipe):
import os
import sys
# Создаем pipe: возвращает два file descriptors
read_fd, write_fd = os.pipe()
pid = os.fork()
if pid == 0: # Дочерний процесс
os.close(read_fd) # Закрываем read конец
os.write(write_fd, b"Hello from child")
os.close(write_fd)
sys.exit(0)
else: # Родительский процесс
os.close(write_fd) # Закрываем write конец
data = os.read(read_fd, 1024)
print(f"Received: {data.decode()}")
os.close(read_fd)
os.wait() # Ждем завершения дочернего процесса
Именованный pipe (named pipe / FIFO):
import os
import sys
# Создаем FIFO
fifo_path = '/tmp/my_fifo'
if os.path.exists(fifo_path):
os.unlink(fifo_path)
os.mkfifo(fifo_path)
# Процесс 1 (writer)
with open(fifo_path, 'w') as fifo:
fifo.write("Data from process 1")
# Процесс 2 (reader) — в отдельном терминале
with open(fifo_path, 'r') as fifo:
data = fifo.read()
print(f"Received: {data}")
2. Signals (сигналы) — асинхронное уведомление
Сигналы — это способ отправить простое уведомление между процессами.
import signal
import os
import time
def signal_handler(signum, frame):
print(f"Received signal {signum}")
if signum == signal.SIGUSR1:
print("Custom signal received")
# Регистрируем обработчик
signal.signal(signal.SIGUSR1, signal_handler)
pid = os.fork()
if pid == 0: # Дочерний процесс
time.sleep(2)
os.kill(os.getppid(), signal.SIGUSR1) # Отправляем сигнал родителю
sys.exit(0)
else: # Родительский процесс
print(f"Child PID: {pid}")
time.sleep(5) # Ждем сигнала
os.wait()
Основные сигналы:
- SIGTERM (15) — graceful shutdown
- SIGKILL (9) — force kill (нельзя перехватить)
- SIGUSR1/SIGUSR2 — кастомные сигналы
- SIGCHLD — уведомление о завершении дочернего процесса
3. Shared Memory (общая память) — быстрый обмен большими данными
import os
import sys
import mmap
import struct
# Размер общей памяти
SHM_SIZE = 1024
SHM_KEY = b'myshm'
pid = os.fork()
if pid == 0: # Дочерний процесс (writer)
# Создаем файл для shared memory
fd = os.open('/tmp/shm_file', os.O_CREAT | os.O_RDWR, 0o666)
os.write(fd, b'\0' * SHM_SIZE)
with os.fdopen(fd, 'r+b') as f:
with mmap.mmap(f.fileno(), SHM_SIZE) as shm:
# Пишем структурированные данные
data = struct.pack('I', 42) # unsigned int
shm.write(data)
shm.flush()
print("Data written to shared memory")
sys.exit(0)
else: # Родительский процесс (reader)
time.sleep(0.5) # Даем время дочернему процессу
with open('/tmp/shm_file', 'r+b') as f:
with mmap.mmap(f.fileno(), SHM_SIZE) as shm:
data = shm[:4]
value = struct.unpack('I', data)[0]
print(f"Read from shared memory: {value}")
os.wait()
os.unlink('/tmp/shm_file')
4. Message Queues (очереди сообщений) — надежная доставка
import posix_ipc
import os
# Создаем очередь сообщений
queue = posix_ipc.MessageQueue('/myqueue', flags=os.O_CREAT)
pid = os.fork()
if pid == 0: # Дочерний процесс (sender)
queue.send(b"Message 1", priority=1)
queue.send(b"Message 2", priority=2)
print("Messages sent")
sys.exit(0)
else: # Родительский процесс (receiver)
msg1, priority1 = queue.receive()
msg2, priority2 = queue.receive()
print(f"Received: {msg1}, priority: {priority1}")
print(f"Received: {msg2}, priority: {priority2}")
queue.close()
queue.unlink()
os.wait()
5. Sockets (сокеты) — сетевое взаимодействие
Unix domain sockets (для локального взаимодействия):
import socket
import os
socket_path = '/tmp/my_socket.sock'
if os.path.exists(socket_path):
os.remove(socket_path)
# Server
server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server_socket.bind(socket_path)
server_socket.listen(1)
pid = os.fork()
if pid == 0: # Client
time.sleep(0.5)
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client.connect(socket_path)
client.send(b"Hello Server")
client.close()
sys.exit(0)
else: # Server
connection, _ = server_socket.accept()
data = connection.recv(1024)
print(f"Received: {data.decode()}")
connection.close()
server_socket.close()
os.wait()
os.remove(socket_path)
6. Сравнение методов IPC
| Метод | Скорость | Надежность | Случай использования |
|---|---|---|---|
| Pipe | Быстро | Низкая | Простой data flow |
| Signals | Очень быстро | Низкая | Уведомления |
| Shared Memory | Очень быстро | Средняя | Большие данные |
| Message Queue | Медленно | Высокая | Критичные данные |
| Sockets | Медленно | Средняя | Сетевое взаимодействие |
7. Практический пример — producer/consumer с Queue
from multiprocessing import Queue, Process
def producer(queue):
for i in range(5):
queue.put(f"Item {i}")
print(f"Produced: Item {i}")
def consumer(queue):
while True:
item = queue.get()
if item is None: # Signal to stop
break
print(f"Consumed: {item}")
if __name__ == '__main__':
queue = Queue()
p1 = Process(target=producer, args=(queue,))
p2 = Process(target=consumer, args=(queue,))
p1.start()
p2.start()
p1.join()
queue.put(None) # Stop signal
p2.join()
Итоговая схема
Выбор метода зависит от требований:
- Простой обмен → Pipes
- Быстрый обмен большими данными → Shared Memory
- Надежная доставка → Message Queues
- Сетевое взаимодействие → Sockets
- Асинхронные уведомления → Signals
В современных приложениях часто используют multiprocessing.Queue или message brokers (RabbitMQ, Redis) вместо низкоуровневых механизмов.