44

有很多与 Stackless Python 相关的问题。但是没有人回答我的问题,我想(如果错了请纠正我 - 请!)。一直有一些关于它的嗡嗡声,所以我很想知道。我会用 Stackless 做什么?它比 CPython 好在哪里?

是的,它有绿色线程(无堆栈),只要没有操作阻塞(类似于 Ruby 的线程?),就可以快速创建许多轻量级线程。这有什么好处?我想通过 CPython 使用它还有哪些其他功能?

4

6 回答 6

32

它允许您处理大量并发。没有理智的人会创建十万个系统线程,但你可以使用无堆栈来做到这一点。

本文测试这样做,在 Python 和 Google Go(一种新的编程语言)中创建十万个 tasklet:http: //dalkescientific.com/writings/diary/archive/2009/11/15/100000_tasklets.html

令人惊讶的是,即使 Google Go 被编译为本地代码,并且他们吹捧他们的协同例程实现,Python 仍然获胜。

Stackless 非常适合实现 map/reduce 算法,根据您的输入数据,您可以拥有大量的 reducer。

于 2010-02-12T01:15:33.287 回答
12

Stackless Python 的主要好处是支持非常轻量级的协程。CPython 本身不支持协程(尽管我希望有人在评论中发布基于生成器的 hack),因此当您遇到受益于协程的问题时,Stackless 是对 CPython 的明显改进。

我认为他们擅长的主要领域是当您在程序中运行许多并发任务时。示例可能是为其 AI 运行循环脚本的游戏实体,或者为许多客户端提供服务的 Web 服务器,其页面创建速度很慢。

您仍然有许多典型的并发正确性问题,但是关于共享数据,但是确定性任务切换使编写安全代码变得更容易,因为您确切地知道控制将被转移到哪里,因此知道共享状态必须处于的确切点最新。

于 2010-02-08T10:58:20.027 回答
9

Thirler 已经提到 Eve Online 中使用了 stackless。请记住,即:

(..) 无堆栈通过允许将任务分成更小的任务 Tasklet 进一步扭曲了这一点,然后可以将这些任务从主程序中分离出来自行执行。这可用于即发即弃的任务,例如发送电子邮件或调度事件,或用于 IO 操作,例如发送和接收网络数据包。一个小任务等待来自网络的数据包,而其他小任务继续运行游戏循环。

它在某些方面类似于线程,但它是非抢占式和显式调度的,因此同步问题较少。此外,tasklet 之间的切换比线程切换要快得多,并且您可以拥有大量活动的 tasklet,而线程的数量受到计算机硬件的严重限制。

(从这里得到这个引文)

在 PyCon 2009 上有一个非常有趣的演讲,描述了 Stackless 为何以及如何在 CCP Games 中使用。

此外,还有一个非常好的介绍材料,它描述了为什么无堆栈是您的应用程序的一个很好的解决方案。(可能有些旧,但我认为值得一读)。

于 2010-02-12T12:50:27.677 回答
6

EVEOnline 主要使用 Stackless Python 进行编程。他们有几个关于使用它的开发博客。它似乎对高性能计算非常有用。

于 2010-02-08T09:51:05.743 回答
6

虽然我没有使用 Stackless 本身,但我使用 Greenlet 来实现高度并发的网络应用程序。Linden Lab 的一些用例包括:高性能智能代理、在大量机器上分配命令的快速系统,以及执行大量数据库写入和读取的应用程序(比率约为 1 :2,写入量很大,因此大部分时间都在等待数据库返回),以及用于内部网络数据的网络爬虫类型的东西。基本上,任何期望必须执行大量网络 I/O 的应用程序都将从能够创建 bajillion 轻量级线程中受益。10,000 个连接的客户对我来说似乎不是什么大不了的事。

不过,Stackless 或 Greenlet 并不是真正的完整解决方案。它们是非常低级的,您将不得不做大量的工作来使用它们构建一个充分利用它们的应用程序。我知道这一点是因为我维护了一个在 Greenlet 之上提供网络和调度层的库,特别是因为使用它编写应用程序要容易得多。现在有很多这样的;我维护 Eventlet,但也有 Concurrence、Chiral,可能还有一些我不知道的。

如果您要编写的那种应用程序听起来像我写的那样,请考虑其中一个库。Stackless 与 Greenlet 的选择比决定哪个库最适合您想要做的事情的需要更重要。

于 2010-02-17T07:50:37.913 回答
5

在我看来,绿色线程的基本用途是实现一个系统,在该系统中,您拥有大量执行高延迟操作的对象。一个具体的例子是与其他机器通信:

def Run():
    # Do stuff
    request_information() # This call might block
    # Proceed doing more stuff

线程让您自然地编写上述代码,但如果对象数量足够大,线程就无法充分执行。但是,即使数量非常大,您也可以使用绿色线程。request_information()以上可以切换到其他工作正在等待并稍后返回的某个调度程序。您可以获得能够调用“阻塞”函数的所有好处,就好像它们在不使用线程的情况下立即返回一样。

如果您想以简单的方式编写代码,这显然对任何类型的分布式计算都非常有用。

多核减少等待锁也很有趣:

def Run():
    # Do some calculations
    green_lock(the_foo)
    # Do some more calculations

green_lock函数基本上会尝试获取锁,如果由于其他内核使用该对象而失败,则该函数将切换到主调度程序。

再次,绿色线程被用于缓解阻塞,允许代码自然编写并且仍然运行良好。

于 2010-02-16T20:50:31.473 回答