进程间通信


进程间通信(Inter - Process Communication,IPC)是指在不同进程之间进行数据交换和协调同步的机制。由于每个进程都有自己独立的内存空间,因此需要借助操作系统提供的特定方法来实现进程间的信息传递。下面详细介绍常见的进程间通信方式。

管道(Pipe)

  • 匿名管道特点:半双工通信,即数据只能在一个方向上流动;只能用于具有亲缘关系的进程(如父子进程)之间。原理:内核会为管道分配一块缓冲区,写进程将数据写入该缓冲区,读进程从缓冲区读取数据。示例代码(Python)

python

import os

r, w = os.pipe()
pid = os.fork()
if pid == 0:
    os.close(r)
    message = b"Hello, parent!"
    os.write(w, message)
    os.close(w)
else:
    os.close(w)
    data = os.read(r, 1024)
    print(f"Received from child: {data.decode()}")
    os.close(r)
  • 命名管道(FIFO)特点:全双工通信,数据可以在两个方向流动;可以在不相关的进程之间进行通信;以文件形式存在于文件系统中。原理:通过创建一个特殊的 FIFO 文件,不同进程可以像读写普通文件一样对其进行读写操作。示例代码(Python)

python

# 写进程
import os

FIFO = 'myfifo'
os.mkfifo(FIFO)
with open(FIFO, 'w') as f:
    f.write('Hello from writer!')

# 读进程
import os

FIFO = 'myfifo'
with open(FIFO, 'r') as f:
    data = f.read()
    print(f"Received: {data}")
os.unlink(FIFO)

消息队列(Message Queue)

  • 特点:消息队列是消息的链表,存放在内核中,由消息队列标识符标识;克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点;可以实现消息的随机查询,消息不一定要以先进先出的次序读取。
  • 原理:进程可以向消息队列中添加消息,也可以从消息队列中读取消息,消息队列会根据消息类型和优先级进行管理。
  • 示例代码(Python)

python

from multiprocessing import Process, Queue

def sender(q):
    q.put('Hello from sender!')

def receiver(q):
    message = q.get()
    print(f"Received: {message}")

if __name__ == '__main__':
    queue = Queue()
    p1 = Process(target=sender, args=(queue,))
    p2 = Process(target=receiver, args=(queue,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

共享内存(Shared Memory)

  • 特点:多个进程可以访问同一块物理内存区域,是最快的一种 IPC 方式;进程直接对共享内存进行读写操作,不需要进行数据的复制,因此效率高;需要进行同步和互斥操作,以避免数据竞争和不一致性问题。
  • 原理:操作系统将同一块物理内存映射到不同进程的虚拟地址空间中,使得这些进程可以直接访问该内存区域。
  • 示例代码(Python)

python

import multiprocessing as mp
import numpy as np

def modify_shared_memory(shm_name, shape, dtype):
    existing_shm = mp.shared_memory.SharedMemory(name=shm_name)
    arr = np.ndarray(shape, dtype=dtype, buffer=existing_shm.buf)
    arr[:] = [i * 2 for i in range(len(arr))]
    existing_shm.close()

if __name__ == '__main__':
    arr = np.array([1, 2, 3, 4, 5])
    shm = mp.shared_memory.SharedMemory(create=True, size=arr.nbytes)
    shm_arr = np.ndarray(arr.shape, dtype=arr.dtype, buffer=shm.buf)
    shm_arr[:] = arr[:]

    p = mp.Process(target=modify_shared_memory, args=(shm.name, arr.shape, arr.dtype))
    p.start()
    p.join()

    print(shm_arr)
    shm.close()
    shm.unlink()

信号量(Semaphore)

  • 特点:信号量是一个计数器,用于控制多个进程对共享资源的访问;主要用于实现进程间的同步和互斥;可以分为二元信号量(用于互斥)和计数信号量(用于资源计数)。
  • 原理:进程在访问共享资源前需要先获取信号量,如果信号量的值大于 0,则可以获取并将信号量的值减 1;如果信号量的值为 0,则进程需要等待,直到信号量的值大于 0。
  • 示例代码(Python)

python

from multiprocessing import Process, Semaphore
import time

semaphore = Semaphore(2)

def worker(id):
    semaphore.acquire()
    print(f"Process {id} acquired the semaphore.")
    time.sleep(2)
    print(f"Process {id} released the semaphore.")
    semaphore.release()

if __name__ == '__main__':
    processes = [Process(target=worker, args=(i,)) for i in range(5)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()

套接字(Socket)

  • 特点:可用于不同主机之间的进程通信,也可用于同一主机上的进程通信;支持多种协议,如 TCP 和 UDP;提供了一种通用的网络编程接口,使得进程可以通过网络进行数据交换。
  • 原理:通过创建套接字,进程可以监听端口、连接到其他套接字,然后进行数据的发送和接收。
  • 示例代码(Python)

python

# 服务器端
import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 8888))
server_socket.listen(1)

print('Waiting for a connection...')
conn, addr = server_socket.accept()
print(f'Connected by {addr}')

data = conn.recv(1024)
print(f'Received: {data.decode()}')

conn.sendall('Hello from server!'.encode())
conn.close()

# 客户端
import socket

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 8888))

client_socket.sendall('Hello from client!'.encode())

data = client_socket.recv(1024)
print(f'Received: {data.decode()}')

client_socket.close()

不同的进程间通信方式适用于不同的场景,开发者需要根据具体需求来选择合适的通信方式。

原文链接:,转发请注明来源!