MST
星途 面试题库

面试题:Python进程间通信之高级难度:管道通信实践

使用Python的`multiprocessing`模块中的管道(Pipe)实现两个进程间的双向通信。一个进程发送一系列数字,另一个进程接收并计算这些数字的平方,然后将结果返回给发送进程。请写出完整代码,并解释代码中涉及的关键步骤和注意事项。
37.9万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试
import multiprocessing


def sender(conn):
    numbers = [1, 2, 3, 4, 5]
    for num in numbers:
        conn.send(num)
        print(f"发送数字: {num}")
    result = conn.recv()
    print(f"接收结果: {result}")
    conn.close()


def receiver(conn):
    squared_results = []
    while True:
        if conn.poll():
            num = conn.recv()
            squared_results.append(num * num)
            if len(squared_results) == 5:
                conn.send(squared_results)
                break
    conn.close()


if __name__ == '__main__':
    parent_conn, child_conn = multiprocessing.Pipe()
    p1 = multiprocessing.Process(target=sender, args=(parent_conn,))
    p2 = multiprocessing.Process(target=receiver, args=(child_conn,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

关键步骤

  1. 创建管道

    parent_conn, child_conn = multiprocessing.Pipe()
    

    使用multiprocessing.Pipe()创建一个管道对象,返回两个连接对象,parent_connchild_conn,分别用于两个进程间的通信。

  2. 定义发送进程

    def sender(conn):
        numbers = [1, 2, 3, 4, 5]
        for num in numbers:
            conn.send(num)
            print(f"发送数字: {num}")
        result = conn.recv()
        print(f"接收结果: {result}")
        conn.close()
    

    发送进程通过管道发送一系列数字,然后等待接收计算后的平方结果。conn.send()用于发送数据,conn.recv()用于接收数据。

  3. 定义接收进程

    def receiver(conn):
        squared_results = []
        while True:
            if conn.poll():
                num = conn.recv()
                squared_results.append(num * num)
                if len(squared_results) == 5:
                    conn.send(squared_results)
                    break
        conn.close()
    

    接收进程不断检查管道是否有数据到达(conn.poll()),如果有数据则接收(conn.recv()),计算平方并存储,当接收到5个数字后,将计算结果发送回发送进程。

  4. 启动进程

    if __name__ == '__main__':
        p1 = multiprocessing.Process(target=sender, args=(parent_conn,))
        p2 = multiprocessing.Process(target=receiver, args=(child_conn,))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
    

    if __name__ == '__main__':块中,创建并启动两个进程,分别传入对应的连接对象。p1.start()p2.start()启动进程,p1.join()p2.join()等待进程执行完毕。

注意事项

  1. if __name__ == '__main__'::在Windows系统上,必须将创建和启动进程的代码放在if __name__ == '__main__':块中,这是因为Windows使用spawn方式启动新进程,需要在主模块中进行必要的初始化。
  2. 管道使用完毕后关闭:在每个进程中,使用完管道连接后需要调用conn.close()关闭连接,避免资源泄漏。
  3. 数据传输的阻塞conn.send()conn.recv()默认是阻塞的。如果发送端在接收端准备好接收之前发送数据,发送端会一直阻塞,直到接收端调用conn.recv()。同样,conn.recv()也会阻塞,直到有数据可用。conn.poll()可用于非阻塞地检查是否有数据可接收。