5

我正在尝试开发一种服务,该服务包含通过IO::Select. 这个想法是处理通过工作线程池产生的 I/O 和/或请求处理需求。

shared在 Perl ( ) 中使数据可跨线程共享的关键字threads::shared有其局限性——句柄引用不在可以共享的原语中。

在我发现无法共享句柄和/或句柄引用之前,计划是有一个select()线程来处理轮询,然后将相关句柄放在ThreadQueue分布在线程池中的某些 s 中以实际执行读取和写入. (当然,我是这样设计的,以便对所使用的实际描述符集的修改select是线程安全的,并且只发生在一个线程中——运行的同一个线程select(),因此显然不会在它运行时进行。)

现在似乎不会发生这种情况,因为句柄本身无法共享,因此轮询以及读取和写入都需要从一个线程中进行。有什么解决方法吗?我指的是跨线程的实际系统调用的分解;显然,有一些方法可以使用队列和缓冲区在其他线程中生成数据并在其他线程中实际发送。

这种情况产生的一个问题是我必须给出select()一个超时,并期望它足够高,不会导致轮询相当大的一组描述符时出现任何问题,同时又足够低,不会在我的计时中引入太多延迟事件循环——不过,我确实明白,如果在轮询过程中检测到实际的 I/O 集成员资格,select()将提前返回,这在一定程度上缓解了问题。我宁愿有某种方式select()从另一个线程中唤醒,但由于无法共享句柄,我无法轻易想到这样做的方法,也看不到这样做的价值;无论如何,其他线程会知道什么时候适合醒来select()

如果没有解决方法,那么在 Perl 中这种类型的服务有什么好的设计模式?我需要相当高的可扩展性和并发 I/O,因此走的是非阻塞路线,而不是仅仅为每个侦听套接字和/或客户端和/或服务器进程生成线程,因为许多人使用更高-这些天来,级别语言在处理套接字时已经习惯了——这似乎是 Java 领域的一种标准做法,似乎没有人关心java.nio.*在面向系统编程的狭窄领域之外。也许这只是我的印象。无论如何,我不想那样做。

那么,从经验丰富的 Perl 系统程序员的角度来看,这些东西应该如何组织呢?单片 I/O 线程 + 纯工作(非 I/O)线程 + 大量队列?某种聪明的hack?除了我已经列举的之外,还有什么需要注意的线程安全问题吗?有没有更好的办法?我在用 C 语言构建此类程序方面拥有丰富的经验,但没有 Perl 习惯用法或运行时特性。

编辑: PS 我肯定想到,也许具有这些性能要求的程序和这种设计根本不应该用 Perl 编写。但是我看到 Perl 产生了很多非常复杂的服务,所以我不确定。

4

1 回答 1

5

排除您的几个更大的设计问题,我可以提供一些跨 perl 线程共享文件句柄的方法。

可以传递$client给线程启动例程或简单地在新线程中引用它:

$client = $server_socket->accept();

threads->new(\&handle_client, $client);
async { handle_client($client) };
# $client will be closed only when all threads' references
# to it pass out of scope.

对于Thread::Queue设计,可以enqueue()使用底层 fd:

$q->enqueue( POSIX::dup(fileno $client) );
# we dup(2) so that $client may safely go out of scope,
# closing its underlying fd but not the duplicate thereof

async {
  my $client = IO::Handle->new_from_fd( $q->dequeue, "r+" );
  handle_client($client);
};

或者可以只使用 fds 和 Perl 的位向量形式select

于 2009-07-02T17:08:36.750 回答