"Pythonic"多线程(并发)语言

3

我现在主要使用Python编程,但是我正在寻找一种更适合多线程的语言(不是JAVA、C#、C或C++)。

当使用Python进行IO绑定时,它的线程效果很好,但是当我进行CPU密集型任务时,它就表现不佳了。

有什么好的建议吗?

谢谢, 詹姆斯


我从未完全理解“主观”界限在哪里,但是该网站有一个政策,即这些主题应该移动到http://programmers.stackexchange.com/或勾选其“社区维基”框。 我认为这个问题符合这样的主题; 您可以通过编辑问题并选中该框来将其转换为CW。 - intuited
1
我也从未清楚地看到“主观”这条线,但在关闭警察找到它之前将此问题变为 CW 可能是个好主意。 - Niki
你为什么决定使用线程(而不是进程)来解决并发需求? - Ben James
1
@James:“我需要局部变量”。请提供详细信息。这通常是一个严重的设计错误。 - S.Lott
到目前为止,你的解释非常模糊。我们需要具体了解你需要什么才能有效地帮助你。 - Sasha Chedygov
显示剩余2条评论
8个回答

7
Clojure很有趣,如果你喜欢这种类型的语言。它是一种在JVM上运行的Lisp语言。尽管是动态类型的,但显然在很多方面与Java的速度相当快。Java互操作性非常方便,尽管本地的Clojure库已经足够好,你不需要大多数情况下使用Java。
它还添加了一些“脚本语言”的特点,比如map(-> Python字典)和vector(-> Python列表),以帮助减少括号狂热的可能性。
哦对了,并发性。它使用一个软件事务内存系统,这本身就非常有趣。额外,额外:阅读所有内容
*: 我认为你可能需要使用“类型提示”来获得许多任务的类似Java的速度。在Clojure中,这非常方便。

4
在开始之前,你想解决什么编程问题? GIL 是否已成为瓶颈?(如果不确定,可能还没有。)
不知道这一点,你会冒着寻找适合你的工具的风险,而不是反过来。
如果你真的、真的知道 GIL 已经成为瓶颈,并且需要跨多个处理器进行计算,则需要考虑以下事项:
  1. 如果您已知道CPU关键部分,请使用Pyrex/Cython进行C类型声明编译,如果可以的话。这将使它们比Python字节码解释更加高效,并作为奖励,允许您在不需要它的部分释放GIL。(教训:在尝试并行化之前,将您的驴子变成赛马。)
  2. 这应该是不言而喻的,但如果您正在使用任何CPU密集型扩展模块,请确保它们没有为您释放GIL。
  3. 对于几乎所有其他内容,请使用内置multiprocessing模块。这提供了与threading大致相同的API和优势,但为您提供真正的进程级并发性:除其他外,这使您可以轻松地将CPU密集型代码协调在多台机器上运行,这对于实际问题变得很大至关重要。

我已经开始使用Cython并移除GIL,目前可以应付......但我想确保我有备选方案。 - James
2
詹姆斯:你能描述一下你问题的限制是什么吗?这听起来很具体,而且可能会极大地影响你所寻找的答案。 - Pi Delport

3

Boo的语法受到Python的启发。但是,这种编程语言有一些不同之处:它是强类型的,并且具有类型推断功能,其最重要的特性可能是开放的编译器管道,即能够创建语法宏(在LISP中的“宏”意义上,而不是C中的“预处理器宏”)。

显然,IronPython非常符合Python风格,与其他.NET语言一样擅长线程处理。


我不知道 boo 有语法宏。很棒。 - intuited
我也不知道。文档上对此有些滞后。我是通过Oren Eini的杰出著作《DSLs in Boo》(www.manning.com/rahien)了解到的。这可能是关于Boo语法宏特性的最佳参考资料。 - Niki

2
EVE Online” 开发人员所使用的 “Stackless Python” 可能很适合。

Stackless Python” 是 Python 编程语言的增强版。它允许程序员享受基于线程的编程的好处,而不会出现传统线程所带来的性能和复杂性问题。Stackless 添加到 Python 中的微线程是一种廉价且轻量级的便利工具,如果使用得当,不仅可以作为组织应用程序或框架的方式,而且通过这样做改善程序结构并促进更易读的代码。


1

为了克服GIL,您可以尝试使用Jython解释Python语言,而不是CPython。


谢谢,但我正在试图摆脱Java。现在正在寻找一种新的语言....(虽然PyPy看起来很有前途) - James
4
嗨,@user386129,jython 和 cpython 类似,都是基于 Java 和 C 语言的实现。 - mykhal
在测试jython(一些小的测试代码)时,我发现它比cPython慢。 - James

1

Python在处理CPU密集型任务时表现不佳,因为Python不是一种非常高效的语言。许多“动态”语言都有这个问题,因为编译器在编译时对程序可以做出的假设受到限制。例如,方法调用可能需要每次查找,以防某人在每次调用之间替换了对象上的方法。

我建议您看看Erlang,尽管它可能不符合您对“Pythonic”的理解。 :-)


1
@James:Pythonic == 有趣?这可能是你能想到的最毫无意义的“Pythonic”定义。 - JesperE
1
@James:是的,Erlang可以编译成本地代码(至少对于x86和其他几种架构)。Erlang进程在一些本地线程之上进行动态调度;这意味着你可以使用非常多的Erlang进程而不消耗任何重要的内核资源。 - JesperE
任何理智的人都会使用本地库进行数字计算,这并不能说明Erlang与Python的相对性能。我不同意比赛结果是明确无误的;在几个基准测试中,Erlang似乎快了一个数量级。 - JesperE
我不认为Erlang很慢。是的,在某些基准测试中它可能表现不佳,但性能远不止于基准测试。我认识很多同时使用Erlang和Python的人,他们中没有人会因为Erlang太慢而选择Python。 - JesperE
你不需要发两次帖子来展示你的热情 :P - Phyo Arkar Lwin
显示剩余6条评论

1

抓住提示。CPU密集型程序也可以分成多个进程。多个进程和通过管道传递状态通常具有出色的性能。

与其随机寻找其他语言,不如这样做:

  1. 将问题分解为可以并发完成的步骤管道。

    在shell中,顶级脚本是这样的:a.py | b.py | c.py | d.py...

  2. 将每个步骤编写为非常小的Python循环,从sys.stdin读取并写入sys.stdout。有趣的是,这是raw_input()print()的默认设置,使事情变得简单。

  3. 测量性能。

你会--正确地--花费所有时间设计你的算法。你会很少花时间编码或学习一种新语言。你会轻松地占用你可用的每个CPU上的每个核心。你不会花时间在线程同步或其他愚蠢的事情上。

这种方法对于“CPU密集型”应用程序非常有效。


我尝试了一下...唯一的问题是我需要一些本地对象,并且不想开始将这些对象进行 pickling 以便从一个解释器传递到另一个解释器。 - James
2
@James:“我需要一些本地对象”。要小心任何需要对共同对象进行共享写访问的设计。这很少是必要的。共享只读访问是一回事——只需使用shelve即可。共享写/变异访问是一个等待发生的问题。继续努力改进你的设计,以消除这种共享可写访问。 - S.Lott

1

你可以直接使用Python 多进程,它镜像了线程的 API 但运行在独立的进程中。可能不支持非 POSIX 系统。对于一般的 CPU 密集型问题,你也可以尝试 Stackless Python(已经提到过)或者 Pyrex


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接