在单个节点/服务器上使用扭曲线程和MapReduce?

2 投票
1 回答
1033 浏览
提问于 2025-04-16 11:52

我对Twisted的线程有点困惑。

我听过、读过不少关于Python中线程和进程的文章、书籍,还参加过几场相关的讲座。我的感觉是,如果不涉及大量的输入输出(IO)操作,或者不需要在不同的工作之间共享内存,那么使用多进程(multiprocessing)可能是更好的选择。

不过,从我目前看到的情况来看,Twisted似乎是使用线程(就是Python的线程模块中的pThreads)。而且Twisted在处理大量数据时表现得非常好。

我有很多进程想在单个节点/服务器上使用Python的MapReduce模式来分配处理。这些进程基本上不进行IO操作,主要是进行大量的计算。

那么,Twisted的反应器(reactor)适合这个工作吗?

1 个回答

6

简单来说,回答你的问题:,twisted 的线程处理并不适合重度处理。

如果你有很多处理任务,twisted 的线程仍然会受到 GIL(全局解释器锁)的限制。简单来说,GIL 让 Python 代码一次只能有一个线程在执行。这意味着你无法在单个多线程的 twisted 进程中充分利用多个核心。虽然一些 C 模块(比如 SciPy 的某些部分)可以释放 GIL 并支持多线程,但与之相关的 Python 代码仍然是单线程的。

twisted 的线程主要用于与阻塞 I/O 模块一起使用。一个典型的例子是数据库 API,因为数据库 API 规范并没有考虑异步使用的情况,大多数数据库模块都遵循这个规范。因此,如果你想在 twisted 应用中使用 PostgreSQL,就必须要么阻塞,要么使用像 twisted.enterprise.adbapi 这样的包装器,它利用 twisted.internet.threads.deferToThread 来允许 SQL 查询在其他操作进行时执行。这样可以让其他 Python 代码运行,因为 socket 模块(以及大多数涉及操作系统 I/O 的模块)在进行系统调用时会释放 GIL。


不过,你可以使用 twisted 来编写一个与多个 twisted(或非 twisted)工作进程通信的 网络 应用。每个工作进程可以处理一些小任务,这样你就不会受到 GIL 的限制,因为每个工作进程都是一个完全独立的进程。主进程可以利用 twisted 的许多异步原语。例如,你可以使用 DeferredList 来等待来自多个工作进程的结果,然后在所有 Deferred 完成时运行响应处理程序(这样你就可以进行你的映射调用)。如果你想走这条路,我建议你看看 twisted.protocols.amp,这是他们的异步消息协议,可以非常简单地用于实现基于网络的 RPC 或 map-reduce。

不过,运行多个不同的进程相比于使用 multiprocessing 有一些缺点:

  1. 你会失去简单的进程管理,
  2. 子进程无法像在 Unix 系统中那样共享内存。

不过对于现代系统来说,第二点通常不是问题,除非你要运行数百个子进程。而第一个问题可以通过使用像 supervisord 这样的进程管理系统来解决。


编辑 如果想了解更多关于 Python 和 GIL 的内容,可以观看 Dave Beazley 的相关讲座(网站视频幻灯片)。

撰写回答