进程间通信(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()
不同的进程间通信方式适用于不同的场景,开发者需要根据具体需求来选择合适的通信方式。