9

我最近正在阅读这篇文档,其中列出了一些可用于实现套接字服务器的策略。即,它们是:

  1. 每个线程为多个客户端提供服务,并使用非阻塞 I/O 和级别触发的就绪通知
  2. 每个线程为多个客户端提供服务,并使用非阻塞 I/O 和就绪更改通知
  3. 每个服务器线程为多个客户端提供服务,并使用异步 I/O
  4. 使用每个服务器线程为一个客户端提供服务,并使用阻塞 I/O
  5. 将服务器代码构建到内核中

现在,我会很感激在 CPython中应该使用哪个提示,我们知道它有一些优点,也有一些缺点。我最感兴趣的是高并发下的性能,是的,当前的一些实现太慢了。

因此,如果我可以从简单的开始,“5”就出来了,因为我不会将任何东西侵入内核。

“4” 看起来它也因为 GIL 而必须出局。当然,您可以在这里使用多处理来代替线程,这确实会带来显着的提升。阻塞 IO 还具有更容易理解的优点。

在这里,我的知识有所减弱:

“1”是传统的选择或轮询,可以简单地与多处理结合。

"2" 是准备更改通知,由较新的 epoll 和 kqueue 使用

“3”我不确定是否有任何具有 Python 包装器的内核实现。

因此,在 Python 中,我们有很多很棒的工具,比如 Twisted。也许它们是一种更好的方法,尽管我已经对 Twisted 进行了基准测试,发现它在多处理器机器上太慢了。我不知道,也许用负载平衡器进行 4 次扭曲可能会做到这一点。任何意见,将不胜感激。

4

6 回答 6

7

asyncore基本上是“1”——它在select内部使用,你只有一个线程处理所有请求。根据文档,它也可以使用poll. (编辑:删除了 Twisted 引用,我认为它使用了 asyncore,但我错了)。

“2”可能是用python-epoll实现的(刚用谷歌搜索过——以前从未见过)。编辑:(来自评论)在 python 2.6 中,选择模块具有 epoll、kqueue 和 kevent 内置(在支持的平台上)。因此,您不需要任何外部库来执行边缘触发服务。

不要排除“4”,因为当线程实际上正在执行或等待 IO 操作时(大部分时间可能),GIL 将被丢弃。如果你有大量的连接当然是没有意义的。如果您有很多处理工作要做,那么 python 可能对这些方案中的任何一个都没有意义。

对于灵活性,也许看看Twisted

在实践中,您的问题归结为您将对请求进行多少处理。如果您有很多处理,并且需要利用多核并行操作,那么您可能需要多个进程。另一方面,如果您只需要侦听大量连接,那么使用少量线程的 select 或 epoll 应该可以工作。

于 2009-03-11T12:07:05.283 回答
3

“叉子”怎么说?(我假设这就是 ForkingMixIn 所做的)如果请求是在“无共享”(数据库或文件系统除外)架构中处理的,fork() 在大多数 *nixes 上启动得很快,你不必担心关于线程的所有愚蠢错误和并发症。

线程是具有过重进程的操作系统强加给我们的一种设计疾病,恕我直言。克隆具有写时复制属性的页表似乎是一个很小的代价,尤其是在您运行解释器的情况下。

抱歉,我不能更具体,但我更像是一个从 Perl 过渡到 Ruby 的程序员(当我在工作中不为大量 Java 苦苦挣扎时)


更新:我终于在“业余时间”中对线程与分叉进行了一些计时。看看这个:

http://roboprogs.com/devel/2009.04.html

扩展: http ://roboprogs.com/devel/2009.12.html

于 2009-03-11T15:07:41.447 回答
3

一种解决方案是gevent。Gevent将基于 libevent 的事件轮询与由 greenlet 实现的轻量级协作任务切换结合在一起。

你得到的是一个事件系统的所有性能和可扩展性,以及阻塞 IO 编程的优雅和简单的模型。

(我不知道关于回答真正老问题的 SO 约定是什么,但我决定还是加我的 2 美分)

于 2010-07-11T03:07:11.470 回答
2

我可以建议其他链接吗?

cogen是一个跨平台的库,用于面向网络的、基于协程的编程,使用来自 python 2.5 的增强生成器。在 cogen 项目的主页上,有几个具有类似目的的项目的链接。

于 2009-03-11T15:06:58.657 回答
1

http://docs.python.org/library/socketserver.html#asynchronous-mixins

至于多处理器(多核)机器。由于GIL而使用 CPython ,每个核心至少需要一个进程才能进行扩展。正如您所说,您需要 CPython,您可能会尝试使用ForkingMixIn. 使用 Linux 2.6 可能会产生一些有趣的结果。

其他方法是使用Stackless Python。EVE就是这样解决的。但我明白这并不总是可能的。

于 2009-03-11T11:30:19.550 回答
1

我喜欢道格拉斯的回答,但顺便说一句......

您可以使用集中式调度线程/进程来侦听就绪通知,select并委托给工作线程/进程池来帮助实现并行目标。

然而,正如 Douglas 所提到的,GIL 不会在最长时间的 I/O 操作期间保留(因为没有发生 Python-API 事情),所以如果您担心响应延迟,您可以尝试移动您的关键部分CPython API 的代码。

于 2009-03-11T12:22:29.630 回答