使用select进行线程间通信的清洁方式

1 投票
2 回答
4355 浏览
提问于 2025-04-17 09:13

我正在尝试用Python实现一个基于FUSE的文件系统,这个文件系统可以从本地和远程来源获取数据。文件系统的操作是由主FUSE线程来处理的:当有请求时,它会直接处理这些请求。

class MyFilesystem(Fuse):
    def read(self, path, size, offset):
        if self._isLocalFile(path):
            return self._localRead(path, size, offset)
        elif self._isRemoteFile(path):
            # get file from server
    # ...

我原本打算在初始化时创建一个第二个线程,这个线程负责保持客户端和服务器之间的通信。命令是双向流动的,所以客户端目前使用一个select()调用来等待任何传入的命令。

class CommsClient(threading.Thread):
    def run(self):
        conn = self._connect()
        while True:
            r, w, e = select.select([conn], [], [], 1.0)
            if conn in r:
                self._handleData(conn)
    # ...

我现在面临的问题是如何连接这两个线程。当文件系统线程处理请求时,它可能需要等待通信线程从服务器返回回复。我觉得一种解决办法是把文件系统线程的请求流或套接字接入到select()调用中,但我不确定套接字是否是线程间通信的最佳选择。我想缩短select()的超时时间并检查一个事件或线程间变量也可以,但我希望这个机制尽可能快。

有没有人知道处理这种情况的最佳方法?

2 个回答

1

如果其他人也能从中受益,我最终使用的解决方案是利用 threading.Event 锁和一个非阻塞的 select() 调用:

class MyFilesystem(Fuse):
    def read(self, path, size, offset):
        if self._isLocalFile(path):
            return self._localRead(path, size, offset)
        elif self._isRemoteFile(path):
            # get file from server
            self.commsThread.requested_file = path
            self.commsThread.done_event.clear()
            self.commsThread.retrieved_file = None
            self.commsThread.request_event.set()

            self.commsThread.done_event.wait()

            return self.commsThread.retrieved_file[offset:offset+size]

class CommsClient(threading.Thread):
    def run(self):
        conn = self._connect()
        while True:
            self.request_event.wait(0.1)
            if self.request_event.is_set():

                conn.request_file(self.requested_file)

            r, w, e = select.select([conn], [], [], 0.0)

            if conn in r:
                self._handleData(conn)
                if self.retrieved_file:
                    self.done_event.set()
    # ...
2

使用套接字进行线程间通信是完全可以的,但它的速度会比用线程和锁结合内存数据结构来实现要慢一些。这里的“慢”是相对的:硬盘操作可能会慢十倍。

虽然这不是对问题的直接回答,但我建议你看看
ØMQ。它非常快,提供的“套接字”可以在不同的传输方式下传递完整的消息,比如在进程内、进程间、TCP和多播,并且支持异步输入输出。

撰写回答