【问题标题】:Erlang-like 'receive' blocking construct in PythonPython 中类似 Erlang 的“接收”阻塞结构
【发布时间】:2018-02-15 19:45:38
【问题描述】:

我正在用 Python 编写一个应用程序,并希望在没有任何状态变量的情况下编写它(排除属性和驻留在函数之外的任何其他变量)。

类比:根据我的 Erlang 经验,我知道,Erlang 有一个简洁的演员模型,作为其中的一部分,它可以阻止“接收”结构。据我了解,这是 gen_server 的底层机制,它允许将状态存储为参数,而不是外部变量。 Python中有这样的东西吗?还是我走错了路?

具体问题:Python 中有没有一种方法可以让我在不使用任何驻留在函数外部的变量的情况下存储状态(在我的情况下为 DB 连接句柄)?我可以使用任何积极维护的框架来实现这一点。

【问题讨论】:

  • 唯一想到的就是 Twisted 框架之类的东西:twistedmatrix.com/trac
  • 嗨 Tomasz,感谢您的回复,是的,您的建议符合我的要求,但 Twisted 似乎是一个网络库。如果您暗示我从每个想要写入/读取 DB 的模块打开一个套接字连接,那将是实现我的目标(双关语)的一种真正“扭曲”的方式:D。我很想知道是否有更优雅的方式来做到这一点。

标签: python python-3.x erlang


【解决方案1】:

我认为您正在寻找的是关于如何以函数式方式编写 Python 的指针,该方式尽可能避免使用全局状态,特别是使其以 Erlang 的方式“反应”的方式是天生的。

在 Python 中通常可以避免全局状态吗?是的,在大多数情况下。但是,有些事情将简单地是全局的,因为它们代表了现实世界的资源,而且您无法摆脱这种情况(但这就是使用队列来顺序化通信的全部意义所在)。当然,这并不意味着您必须让两个并发线程写入同一个套接字。然而,这确实意味着,您可以在对全局状态没有太多可见性的情况下生成线程或分叉进程,并以它们在内部开发自己的状态的方式编写它们(无论如何这是正常的事情)。

是否可以让 Python 以“反应式”的方式工作?当然。 Python 有一些“反应式”框架,许多编码人员(包括我自己)发现 Python 在以 limited (or no) use of the class keyword 的函数式编写时最易于维护和理解。将两者放在一起,您可能会接近您的目标。我从未使用过它,但ReactiveX for Python 似乎是朝着这个方向发展的。这里还有一个关于 SO 的答案,可能会给你一些思考。

那么可行吗?是的。但可取吗?这完全取决于你试图解决的实际问题,你没有表达出来。这很可能意味着这是一个 X-Y 问题,您需要先解决 X 问题,然后才能以理智的方式继续前进。

当心不适合语言的范式。我个人并不认为 Python 的优势在于这方面,我也不认为 Python 的(缺乏)错误恢复策略有利于并发网络编程。并发编程壁橱里有许多个大而可怕的怪物,共享数据只是其中之一——调度、访问、资源控制、队列溢出管理、排序、排序瓶颈等都会出现他们的头在某个时候。

有一个 原因 Python 有一个 GIL,并且有一个 原因 人们发现在大多数单线程语言(如 Python)中解决大规模并发问题的最佳解决方案是使用 OS 线程结合 Docker 之类的东西来强制进行任意系统分区,采用某种恢复方法,并将调度和资源管理推迟到底层主机操作系统(即使这些影响在很大程度上是大多数人无意识的成就) Docker 社区)。

这些都是超级难题,您不希望将这些超级难题的解决方案写入您开发的每个项目中。

事实证明,Erlang 运行时已经理所当然地提供了所有这些,因为这些正是它旨在解决的问题。这里的差异比 OOP 和 FP coding 范式要深得多,并且真正触及到the underlying runtime and resource management paradigm(在正常情况下,这种性质的讨论中神秘地省略了它)。如果需要响应式、大规模并发是您的问题,我建议您将 Erlang 用于您的项目——但也许 Python 用于在 Python 中更好地表达的部分(特别是如果已经有 Python 库可以完成您需要的任何繁重工作) .

【讨论】:

  • 您好 zxq9,感谢您的出色解释。您的第一段很好地总结了我的要求。我想编写避免全局状态的 FP 代码。我爱上了 Erlang 的无副作用保证,它伴随着编写完全依赖于它的参数的函数。我没有尝试实现任何并发,因为我正在编写一个简单的爬虫(客户端,而不是服务器)。想要以没有副作用的方式编写 Python 代码。你对此有何建议?反应式X?今天会看看它并恢复。
  • @ameyazing 如果您在客户端,那么这非常更容易解决。如果您正在并行访问,请考虑让每个线程产生其请求目标,打开自己的套接字,并在其工作完成时终止(同时,最多只共享对具有队列的记录器/顺序工作者的引用您附加的)。如果您只是在编写单线程程序,那么 socket 编程已经是响应式的,您无需担心。以函数式编写,迭代你的目标,就是这样。不需要魔法库或框架!
  • 我不明白您的评论“让每个线程产生其请求目标”。我认为 Python 不支持多线程。无论如何,此时性能不在我的优先级列表中。我可以接受单线程访问。 Rx 看起来很有希望。很快就会试一试。谢谢。
  • @ameyazing Python 中的多线程可以工作,但存在与 GIL 和数据访问相关的某些限制。 IMO,考虑到 Erlang 的存在和通过套接字进行互操作的便利性(BERT 很好),我只是没有发现 Python 中的多线程和多处理是一个巨大的胜利。它只是不是 OOPy 语言的优势。
猜你喜欢
  • 1970-01-01
  • 2011-05-03
  • 2022-12-03
  • 1970-01-01
  • 2012-02-26
  • 2016-07-16
  • 1970-01-01
  • 2012-08-24
  • 1970-01-01
相关资源
最近更新 更多