标签归档:gevent

GreenletVS。线程数

问题:GreenletVS。线程数

我是gevents和greenlets的新手。我找到了一些有关如何使用它们的很好的文档,但是没有一个文档为我提供有关如何以及何时使用greenlets的理由!

  • 他们真正擅长的是什么?
  • 是否在代理服务器中使用它们是一个好主意吗?
  • 为什么不线程?

我不确定的是,如果它们基本上是例程,它们如何为我们提供并发性。

I am new to gevents and greenlets. I found some good documentation on how to work with them, but none gave me justification on how and when I should use greenlets!

  • What are they really good at?
  • Is it a good idea to use them in a proxy server or not?
  • Why not threads?

What I am not sure about is how they can provide us with concurrency if they’re basically co-routines.


回答 0

Greenlets提供并发性,但提供并行性。并发是指代码可以独立于其他代码运行的时间。并行是同时执行并发代码。当在用户空间中有很多工作要做时,并行性特别有用,而这通常是占用大量CPU的工作。并发对于解决问题非常有用,它可以更轻松地并行调度和管理不同的部分。

Greenlets确实在网络编程中大放异彩,其中与一个套接字的交互可以独立于与其他套接字的交互而发生。这是并发的经典示例。由于每个greenlet都在其自己的上下文中运行,因此您可以继续使用同步API,而无需使用线程。这很好,因为就虚拟内存和内核开销而言,线程非常昂贵,因此线程可以实现的并发性要少得多。此外,由于使用GIL,Python中的线程比平时更昂贵且更受限制。并发的替代方法通常是Twisted,libevent,libuv,node.js等项目,其中所有代码共享相同的执行上下文,并注册事件处理程序。

使用greenlet(具有适当的网络支持,例如通过gevent)来编写代理是一个好主意,因为对请求的处理可以独立执行,因此应这样编写。

出于我之前提到的原因,Greenlets提供了并发性。并发不是并行性。通过隐藏事件注册并为通常会阻塞当前线程的调用执行调度,gevent之类的项目无需更改异步API即可公开此并发性,而系统的成本却大大降低。

Greenlets provide concurrency but not parallelism. Concurrency is when code can run independently of other code. Parallelism is the execution of concurrent code simultaneously. Parallelism is particularly useful when there’s a lot of work to be done in userspace, and that’s typically CPU-heavy stuff. Concurrency is useful for breaking apart problems, enabling different parts to be scheduled and managed more easily in parallel.

Greenlets really shine in network programming where interactions with one socket can occur independently of interactions with other sockets. This is a classic example of concurrency. Because each greenlet runs in its own context, you can continue to use synchronous APIs without threading. This is good because threads are very expensive in terms of virtual memory and kernel overhead, so the concurrency you can achieve with threads is significantly less. Additionally, threading in Python is more expensive and more limited than usual due to the GIL. Alternatives to concurrency are usually projects like Twisted, libevent, libuv, node.js etc, where all your code shares the same execution context, and register event handlers.

It’s an excellent idea to use greenlets (with appropriate networking support such as through gevent) for writing a proxy, as your handling of requests are able to execute independently and should be written as such.

Greenlets provide concurrency for the reasons I gave earlier. Concurrency is not parallelism. By concealing event registration and performing scheduling for you on calls that would normally block the current thread, projects like gevent expose this concurrency without requiring change to an asynchronous API, and at significantly less cost to your system.


回答 1

拿@Max的答案并为其添加一些相关性以进行缩放,您可以看到区别。我是通过更改要填充的URL来实现的,如下所示:

URLS_base = ['www.google.com', 'www.example.com', 'www.python.org', 'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org']
URLS = []
for _ in range(10000):
    for url in URLS_base:
        URLS.append(url)

在我有500个版本之前,我不得不放弃多进程版本。但经过10,000次迭代:

Using gevent it took: 3.756914
-----------
Using multi-threading it took: 15.797028

因此,您可以看到使用gevent的I / O有一些明显的不同

Taking @Max’s answer and adding some relevance to it for scaling, you can see the difference. I achieved this by changing the URLs to be filled as follows:

URLS_base = ['www.google.com', 'www.example.com', 'www.python.org', 'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org']
URLS = []
for _ in range(10000):
    for url in URLS_base:
        URLS.append(url)

I had to drop out the multiprocess version as it fell before I had 500; but at 10,000 iterations:

Using gevent it took: 3.756914
-----------
Using multi-threading it took: 15.797028

So you can see there is some significant difference in I/O using gevent


回答 2

纠正上面的@TemporalBeing的答案,greenlets的速度并不比线程“快”,并且产生60000个线程来解决并发问题是不正确的编程技术,相反,较小的线程池是合适的。这是一个更合理的比较(根据我在reddit帖子中对有人引用此SO帖子的回应)。

import gevent
from gevent import socket as gsock
import socket as sock
import threading
from datetime import datetime


def timeit(fn, URLS):
    t1 = datetime.now()
    fn()
    t2 = datetime.now()
    print(
        "%s / %d hostnames, %s seconds" % (
            fn.__name__,
            len(URLS),
            (t2 - t1).total_seconds()
        )
    )


def run_gevent_without_a_timeout():
    ip_numbers = []

    def greenlet(domain_name):
        ip_numbers.append(gsock.gethostbyname(domain_name))

    jobs = [gevent.spawn(greenlet, domain_name) for domain_name in URLS]
    gevent.joinall(jobs)
    assert len(ip_numbers) == len(URLS)


def run_threads_correctly():
    ip_numbers = []

    def process():
        while queue:
            try:
                domain_name = queue.pop()
            except IndexError:
                pass
            else:
                ip_numbers.append(sock.gethostbyname(domain_name))

    threads = [threading.Thread(target=process) for i in range(50)]

    queue = list(URLS)
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    assert len(ip_numbers) == len(URLS)

URLS_base = ['www.google.com', 'www.example.com', 'www.python.org',
             'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org']

for NUM in (5, 50, 500, 5000, 10000):
    URLS = []

    for _ in range(NUM):
        for url in URLS_base:
            URLS.append(url)

    print("--------------------")
    timeit(run_gevent_without_a_timeout, URLS)
    timeit(run_threads_correctly, URLS)

结果如下:

--------------------
run_gevent_without_a_timeout / 30 hostnames, 0.044888 seconds
run_threads_correctly / 30 hostnames, 0.019389 seconds
--------------------
run_gevent_without_a_timeout / 300 hostnames, 0.186045 seconds
run_threads_correctly / 300 hostnames, 0.153808 seconds
--------------------
run_gevent_without_a_timeout / 3000 hostnames, 1.834089 seconds
run_threads_correctly / 3000 hostnames, 1.569523 seconds
--------------------
run_gevent_without_a_timeout / 30000 hostnames, 19.030259 seconds
run_threads_correctly / 30000 hostnames, 15.163603 seconds
--------------------
run_gevent_without_a_timeout / 60000 hostnames, 35.770358 seconds
run_threads_correctly / 60000 hostnames, 29.864083 seconds

每个人对使用Python进行非阻塞IO的误解都认为,Python解释器可以比网络连接本身返回IO的速度更快地完成从套接字检索结果的工作。尽管在某些情况下这确实是正确的,但事实并非如人们想象的那么频繁,因为Python解释器的确非常慢。在我的博客文章中,我说明了一些图形配置文件,这些图形配置文件显示即使对于非常简单的事情,如果您要处理对数据库或DNS服务器等事物的快速便捷的网络访问,这些服务的返回速度都将比Python代码快得多。可以参加成千上万的此类联系。

Correcting for @TemporalBeing ‘s answer above, greenlets are not “faster” than threads and it is an incorrect programming technique to spawn 60000 threads to solve a concurrency problem, a small pool of threads is instead appropriate. Here is a more reasonable comparison (from my reddit post in response to people citing this SO post).

import gevent
from gevent import socket as gsock
import socket as sock
import threading
from datetime import datetime


def timeit(fn, URLS):
    t1 = datetime.now()
    fn()
    t2 = datetime.now()
    print(
        "%s / %d hostnames, %s seconds" % (
            fn.__name__,
            len(URLS),
            (t2 - t1).total_seconds()
        )
    )


def run_gevent_without_a_timeout():
    ip_numbers = []

    def greenlet(domain_name):
        ip_numbers.append(gsock.gethostbyname(domain_name))

    jobs = [gevent.spawn(greenlet, domain_name) for domain_name in URLS]
    gevent.joinall(jobs)
    assert len(ip_numbers) == len(URLS)


def run_threads_correctly():
    ip_numbers = []

    def process():
        while queue:
            try:
                domain_name = queue.pop()
            except IndexError:
                pass
            else:
                ip_numbers.append(sock.gethostbyname(domain_name))

    threads = [threading.Thread(target=process) for i in range(50)]

    queue = list(URLS)
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    assert len(ip_numbers) == len(URLS)

URLS_base = ['www.google.com', 'www.example.com', 'www.python.org',
             'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org']

for NUM in (5, 50, 500, 5000, 10000):
    URLS = []

    for _ in range(NUM):
        for url in URLS_base:
            URLS.append(url)

    print("--------------------")
    timeit(run_gevent_without_a_timeout, URLS)
    timeit(run_threads_correctly, URLS)

Here are some results:

--------------------
run_gevent_without_a_timeout / 30 hostnames, 0.044888 seconds
run_threads_correctly / 30 hostnames, 0.019389 seconds
--------------------
run_gevent_without_a_timeout / 300 hostnames, 0.186045 seconds
run_threads_correctly / 300 hostnames, 0.153808 seconds
--------------------
run_gevent_without_a_timeout / 3000 hostnames, 1.834089 seconds
run_threads_correctly / 3000 hostnames, 1.569523 seconds
--------------------
run_gevent_without_a_timeout / 30000 hostnames, 19.030259 seconds
run_threads_correctly / 30000 hostnames, 15.163603 seconds
--------------------
run_gevent_without_a_timeout / 60000 hostnames, 35.770358 seconds
run_threads_correctly / 60000 hostnames, 29.864083 seconds

the misunderstanding everyone has about non-blocking IO with Python is the belief that the Python interpreter can attend to the work of retrieving results from sockets at a large scale faster than the network connections themselves can return IO. While this is certainly true in some cases, it is not true nearly as often as people think, because the Python interpreter is really, really slow. In my blog post here, I illustrate some graphical profiles that show that for even very simple things, if you are dealing with crisp and fast network access to things like databases or DNS servers, those services can come back a lot faster than the Python code can attend to many thousands of those connections.


回答 3

这足以分析有趣。这是一个代码,用于比较greenlet与多处理池与多线程的性能:

import gevent
from gevent import socket as gsock
import socket as sock
from multiprocessing import Pool
from threading import Thread
from datetime import datetime

class IpGetter(Thread):
    def __init__(self, domain):
        Thread.__init__(self)
        self.domain = domain
    def run(self):
        self.ip = sock.gethostbyname(self.domain)

if __name__ == "__main__":
    URLS = ['www.google.com', 'www.example.com', 'www.python.org', 'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org']
    t1 = datetime.now()
    jobs = [gevent.spawn(gsock.gethostbyname, url) for url in URLS]
    gevent.joinall(jobs, timeout=2)
    t2 = datetime.now()
    print "Using gevent it took: %s" % (t2-t1).total_seconds()
    print "-----------"
    t1 = datetime.now()
    pool = Pool(len(URLS))
    results = pool.map(sock.gethostbyname, URLS)
    t2 = datetime.now()
    pool.close()
    print "Using multiprocessing it took: %s" % (t2-t1).total_seconds()
    print "-----------"
    t1 = datetime.now()
    threads = []
    for url in URLS:
        t = IpGetter(url)
        t.start()
        threads.append(t)
    for t in threads:
        t.join()
    t2 = datetime.now()
    print "Using multi-threading it took: %s" % (t2-t1).total_seconds()

结果如下:

Using gevent it took: 0.083758
-----------
Using multiprocessing it took: 0.023633
-----------
Using multi-threading it took: 0.008327

我认为greenlet声称它不像多线程库那样不受GIL的约束。而且,Greenlet doc说它是用于网络操作的。对于网络密集型操作,线程切换很好,您可以看到多线程方法非常快。同样,使用python的官方库总是很可取的。我尝试在Windows上安装greenlet并遇到dll依赖关系问题,因此我在linux vm上运行了该测试。始终尝试编写代码,希望它可以在任何计算机上运行。

This is interesting enough to analyze. Here is a code to compare performance of greenlets versus multiprocessing pool versus multi-threading:

import gevent
from gevent import socket as gsock
import socket as sock
from multiprocessing import Pool
from threading import Thread
from datetime import datetime

class IpGetter(Thread):
    def __init__(self, domain):
        Thread.__init__(self)
        self.domain = domain
    def run(self):
        self.ip = sock.gethostbyname(self.domain)

if __name__ == "__main__":
    URLS = ['www.google.com', 'www.example.com', 'www.python.org', 'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org']
    t1 = datetime.now()
    jobs = [gevent.spawn(gsock.gethostbyname, url) for url in URLS]
    gevent.joinall(jobs, timeout=2)
    t2 = datetime.now()
    print "Using gevent it took: %s" % (t2-t1).total_seconds()
    print "-----------"
    t1 = datetime.now()
    pool = Pool(len(URLS))
    results = pool.map(sock.gethostbyname, URLS)
    t2 = datetime.now()
    pool.close()
    print "Using multiprocessing it took: %s" % (t2-t1).total_seconds()
    print "-----------"
    t1 = datetime.now()
    threads = []
    for url in URLS:
        t = IpGetter(url)
        t.start()
        threads.append(t)
    for t in threads:
        t.join()
    t2 = datetime.now()
    print "Using multi-threading it took: %s" % (t2-t1).total_seconds()

here are the results:

Using gevent it took: 0.083758
-----------
Using multiprocessing it took: 0.023633
-----------
Using multi-threading it took: 0.008327

I think that greenlet claims that it is not bound by GIL unlike the multithreading library. Moreover, Greenlet doc says that it is meant for network operations. For a network intensive operation, thread-switching is fine and you can see that the multithreading approach is pretty fast. Also it’s always prefeerable to use python’s official libraries; I tried installing greenlet on windows and encountered a dll dependency problem so I ran this test on a linux vm. Alway try to write a code with the hope that it runs on any machine.


何时使用龙卷风,何时使用Twisted / Cyclone / GEvent /其他[关闭]

问题:何时使用龙卷风,何时使用Twisted / Cyclone / GEvent /其他[关闭]

以下哪个框架/库是构建现代多用户Web应用程序的最佳选择?我很想拥有一个异步Web服务器,这将使我可以轻松扩展。哪种解决方案将提供最佳的性能 / 可伸缩性 / 最有用的框架(就易于使用和易于开发而言)?

如果它将提供良好的功能(websockets,rpc,流式传输等),那就太好了。

每个解决方案的优缺点是什么?

Which of these frameworks / libraries would be the best choise for building modern multiuser web application? I would love to have an asynchronous webserver which will allow me to scale easly. What solution will give the best performance / scalability / most useful framework (in terms of easy of use and easy of developing)?

It would be great if it will provide good functionality (websockets, rpc, streaming, etc).

What are the pros and cons of each solution?


回答 0

Django是一个高级Python Web框架,它鼓励快速开发和简洁实用的设计”。如果您要构建类似于电子商务站点的内容,则可能应该使用Django。它将使您的工作迅速完成。您不必担心太多的技术选择。它提供了从模板引擎到ORM所需的一切。对于您构建应用程序的方式,我们会有些怀疑,如果您问我,这很好。它具有所有其他图书馆中最强大的社区,这意味着可以轻松获得帮助。

Flask是基于Werkzeug,Jinja 2和良好意图的Python微框架”。当心-“微框架”可能会产生误导。这并不意味着Flask是一个半熟的库。这意味着烧瓶的核心非常非常简单。与Django不同,它将不会为您做出任何技术决策。您可以自由选择任何令您满意的模板引擎或ORM。即使默认情况下它带有Jinja模板引擎,您仍然可以自由选择我们自己的。据我所知,Flask可用于编写API端点(RESTful服务)。

Twisted是一个用python编写的事件驱动的网络引擎”。这是高性能的引擎。其速度的主要原因是所谓的延迟。Twisted建立在延期之上。对于那些不了解延迟的人来说,这是通过异步体系结构实现的机制。扭曲非常快。但是不适合编写常规的Webapp。如果您想做一些底层的网络工作,那么twisted是您的朋友。

Tornado是一个Python Web框架和异步网络库,最初是由FriendFeed开发的。通过使用非阻塞网络I / O,Tornado可以扩展到成千上万的开放连接,使其非常适合长时间轮询,WebSocket和其他应用程序需要与每个用户建立长期连接”。龙卷风位于Django和Flask之间。如果您想用Django或Flask编写东西,但是如果您需要更好的性能,则可以选择Tornado。如果架构正确,它可以很好地处理C10k问题。

Cyclone是用于Python的Web服务器框架,它实现了Tornado API作为Twisted协议的实现”。现在,如果您想要具有与Twisted差不多的性能但易于编写的常规Web应用程序,该怎么办?向飓风打个招呼。我更喜欢飓风而不是龙卷风。它具有与Tornado非常相似的API。实际上,这是龙卷风的叉子。但是问题是它的社区相对较小。Alexandre Fiori是回购协议的唯一主要提交者。

Pyramid是一个通用的开源Python Web应用程序开发框架。其主要目标是使Python开发人员更轻松地创建Web应用程序。” 我并没有真正使用过金字塔,但是我浏览了文档。据我了解,金字塔与Flask非常相似,我认为您可以在任何地方使用金字塔 Flask合适的,反之亦然。

编辑:欢迎要求审查任何其他框架!

资料来源:http : //dhilipsiva.com/2013/05/19/python-libraries-django-twisted-tornado-flask-cyclone-and-pyramid.html

Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design”. If you are building something that is similar to a e-commerce site, then you should probably go with Django. It will get your work done quick. You dont have to worry about too many technology choices. It provides everything thing you need from template engine to ORM. It will be slightly opinionated about the way you structure your app, which is good If you ask me. And it has the strongest community of all the other libraries, which means easy help is available.

Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions”. Beware – “microframework” may be misleading. This does not mean that Flask is a half-baked library. This mean the core of flask is very, very simple. Unlike Django, It will not make any Technology decisions for you. You are free to choose any template engine or ORM that pleases you. Even though it comes with Jinja template engine by default, you are always free to choose our own. As far as I know Flask comes in handy for writing APIs endpoints (RESTful services).

Twisted is an event-driven networking engine written in python”. This is a high-performance engine. The main reason for its speed is something called as deferred. Twisted is built on top of deferreds. For those of you who dont know about defereds, it is the mechanism through with asynchronous architecture is achieved. Twisted is very fast. But is not suitable for writing conventional webapps. If you want to do something low-level networking stuff, twisted is your friend.

Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed. By using non-blocking network I/O, Tornado can scale to tens of thousands of open connections, making it ideal for long polling, WebSockets, and other applications that require a long-lived connection to each user”. Tornado stands some where between Django and Flask. If you want to write something with Django or Flask, but if you need a better performance, you can opt for Tornado. it can handle C10k problem very well if it is architected right.

Cyclone is a web server framework for Python that implements the Tornado API as a Twisted protocol”. Now, what if you want something that is nearly as performant as Twisted but easy to write conventional webapps? Say hello to cyclone. I would prefer Cyclone over Tornado. It has an API that is very similar to Tornado. As a matter of fact, this is a fork of Tornado. But the problem is it has relativly small community. Alexandre Fiori is the only main commiter to the repo.

Pyramid is a general, open source, Python web application development framework. Its primary goal is to make it easier for a Python developer to create web applications.” I haven’t really used Pyramid, but I went through the documentation. From what I understand, Pyramid is very similar to Flask and I think you can use Pyramid wherever Flask seems appropriate and vice-versa.

EDIT: Request to review any other frameworks are welcomed!

Source: http://dhilipsiva.com/2013/05/19/python-libraries-django-twisted-tornado-flask-cyclone-and-pyramid.html


回答 1

这显然是一个有偏见的答案,但这与错误的答案不同。您应该始终使用Twisted。我之前也回答过类似的问题,但是由于您的问题并不完全相同,因此有一些原因:

“最棒的表演”

Twisted在speed.twistedmatrix.com网站上持续监控我们的表现。我们也是PyPy的类似网站监控的首批项目之一,从而确保Twisted在运行时的良好性能,这是任何关注Python中高性能应用程序的人的。

“可伸缩性”

据我所知,列出的框架都没有内置的自动缩放支持。它们都是通信框架,因此您必须进行工作以在扩展节点之间进行通信。但是,Twisted在其对本地多处理的内置支持方面具有优势。公平地说,Tornado一个第三方加载项,使您可以执行相同的操作。在最新发行版中,Twisted添加了功能,这些功能增加了内核之间共享工作的方式数量,并且该领域的工作正在进行中。扭曲的也有一对夫妇的良好整合“本土” RPC它提供了一个建筑套件,无论缩放成语你想追求的协议。

“最有用”

很多人似乎发现Twisted 非常有用如此之多,以至于其中许多人都对其进行了扩展,并向您提供了其扩展名。

“功能”

开箱即用,Twisted包括:

至少在最后一个部门中,Twisted似乎是内置功能的明显赢家。而这一切,仅需2兆字节即可!

This is obviously a somewhat biased answer, but that is not the same thing as a wrong answer; you should always use Twisted. I’ve answered similar questions before, but since your question is not quite the same, here are some reasons:

“Best Performance”

Twisted continuously monitors our performance at the speed.twistedmatrix.com website. We were also one of the first projects to be monitored by PyPy’s similar site, thereby assuring the good performance of Twisted on the runtime that anyone concerned with high-performance applications in Python.

“Scalability”

To my knowledge, none of the listed frameworks have any built-in support for automatic scaling; they’re all communication frameworks, so you have to do the work to communicate between your scaling nodes. However, Twisted has an advantage in its built-in support for local multi-processing. In fairness, there is a third-party add-on for Tornado that allows you to do the same thing. In recent releases, Twisted has added features that increase the number of ways you can share work between cores, and work is ongoing in that area. Twisted also has a couple of well-integrated, “native” RPC protocols which offer a construction-kit for whatever scaling idiom you want to pursue.

“Most Useful”

Lots of people seem to find Twisted very useful. So much so that many of them have extended it and made their extensions available to you.

“Functionality”

Out of the box, Twisted includes:

In this last department, at least, Twisted seems a clear winner for built-in functionality. And all this, in a package just over 2 megabytes!


回答 2

我喜欢@Glyph回复。Twisted非常全面,丰富的python框架。Twisted和Tornado具有非常相似的设计。我非常喜欢这种设计:

  • 它很快
  • 容易理解
  • 易于扩展
  • 不需要 c扩展名
  • 在PyPy上工作。

但是,我想强调Tornado,我更喜欢它,最近又变得流行。与Twisted类似,Tornado使用回调样式编程,但是可以使用tornado.gen.enginetwisted.internet.inlineCallbacks在Twisted中)。

程式库

最佳评论来自http://cyclone.io网站。气旋试图混合扭曲和龙卷风,因为:

Twisted是最公开的非阻塞I / O库之一。Tornado是FriendFeed的Web服务器的开源版本,它是Python最受欢迎,最快速的Web服务器之一,并具有用于构建Web应用程序的非常不错的API。

这个想法是将Tornado优雅而直接的API桥接到Twisted的Event-Loop,从而实现大量受支持的协议。

但是在2011年 tornado.platform.twisted年问世,它带来了类似的功能。

性能

龙卷风有更好的表现。它还可以与PyPy无缝协作,并获得巨大收益。

可扩展性

像扭曲一样。龙卷风有tornado.process在其上实现了许多rpc服务。

功能性

有71种基于Tornado的软件包,而148种Twisted和48 Gevent的软件包。但是,如果仔细查看并计算软件包上载时间的中位数,您会发现Twisted最早,而Gevent和Tornado最新鲜。此外,还有一个tornado.platform.twisted模块,允许您运行为Twisted on Tornado编写的代码

摘要

使用Tornado,您可以使用Twisted中的代码。无需使用只会扭曲的旋风分离器您的代码的(您的代码会变得更加混乱)。

至于2014年,Tornado被认为是广泛接受的默认异步框架,可同时在python2和python3上使用。另外,最新版本4.x带来了https://docs.python.org/dev/library/asyncio.html中的许多功能。

我写了一篇文章,解释了为什么我认为Tornado是最好的Python Web框架,在那里我写了很多有关Tornado功能的信息。

I like @Glyph response. Twisted is very comprehensive, rich python framework. Twisted and Tornado have a very similar design. And I like this design very much:

  • it’s fast
  • easy to understand
  • easy to extend
  • doesn’t require c-extensions
  • works on PyPy.

But I want to highlight Tornado, which I prefer and recently gain popularity. Tornado, like Twisted, uses callback style programming, but it can be inlined using tornado.gen.engine (twisted.internet.inlineCallbacks in Twisted).

Codebase

The best comment is from http://cyclone.io site. cyclone tries to mix Twisted and Tornado because:

Twisted is one of the most mature libraries for non-blocking I/O available to the public. Tornado is the open source version of FriendFeed’s web server, one of the most popular and fast web servers for Python, with a very decent API for building web applications.

The idea is to bridge Tornado’s elegant and straightforward API to Twisted’s Event-Loop, enabling a vast number of supported protocols.

But in 2011 tornado.platform.twisted was out which brings similar functionality.

Performance

Tornado has much better performance. It also works seamlessly with PyPy, and get huge gain.

Scalability

The same like Twisted. Tornado has tornado.process and a lot of rpc services implemented on top of it.

Functionality

There are 71 Tornado based package, compared to 148 Twisted’s and 48 Gevent’s. But if you look carefully and compute median of packages upload time, you will see that Twisted ones are the oldest, then Gevent and Tornado the freshest. Furthermore there is tornado.platform.twisted module which allows you to run code written for Twisted on Tornado.

Summary

With Tornado you can use a code from Twisted. There is no need to use cyclone which only twists your code (your code becomes more messy).

As for 2014, Tornado is considered as widely accepted and default async framework which works both on python2 and python3. Also the latest version 4.x brings a lot of functionality from https://docs.python.org/dev/library/asyncio.html.

I wrote an article, explaining why I consider that Tornado – the best Python web framework where I wrote much more about Tornado functionality.


回答 3

更新:我对这里推荐甚至提到Gevent的答案很少感到惊讶,我认为这与这个出色的库的受欢迎程度,性能和易用性不成比例!)

Gevent和Twisted并不是互斥的,尽管乍一看似乎相反。有一个名为的项目geventreactor,可以使人们相对平稳地利用两全其美的优势,即:

  • Gevent的高效,廉价(绿色协作)线程模型,在并发方面更容易编程—坦率地说,inlineCallbacks对于许多协同程序,Twisted的性能根本无法胜任,在易用性/透明度方面:yieldDeferreds无处不在; 通常很难建立一些抽象;带有Deferred,甚至还有的可怕的无用堆栈跟踪@inlineCallbacks
  • 您可以梦想得到的Twisted的所有内置功能,包括但不限于IReactorProcess.spawnProcess

我目前个人使用Gevent 1.0rc2和Twisted 12.3桥接geventreactor。我已经实现了我自己尚未发布的增补和增强功能geventreactor,我将很快对其进行发布,希望作为geventreactor原始GitHub存储库的一部分:https : //github.com/jyio/geventreactor

我目前的布局可以让我在节目中GEVENT漂亮的编程模型,并利用的东西,如非阻塞socketurllib2和其他模块。我可以使用常规的Python代码来完成常规的工作,而不是通过Twisted方式来学习曲线和简单甚至基本的工作带来的不便。我也可以轻松地使用大多数第三方库,这些库通常对于Twisted来说是毫无疑问的,或者需要使用线程。

我还可以通过使用greenlets(而不是Deferreds和callbacks和/或@inlineCallbacks)完全避免笨拙且通常过于复杂的基于回调的编程。

(此答案是根据我在现实生活项目中同时使用Twisted和Gevent的个人经验编写的,并且使用Twisted的经验也很多(但我并没有声称自己是Twisted专家)。我必须编写hasn的软件不必使用Twisted的太多功能,因此根据Twisted所需的功能集,混合Gevent和Twisted的(相对轻松)额外的复杂性可能不值得。

(UPDATE: I’m sadly surprised about how few answers here recommend or even mention Gevent—I don’t think it’s in proportion to the popularity, performance and ease of use of this excellent library!)

Gevent and Twisted are not mutually exclusive, even though the contrary might seem obvious at first. There is a project called geventreactor which allows one to relatively smoothly leverage the best of both worlds, namely:

  • The efficient and cheap (cooperative green) thread model of Gevent, which is much easier to program in when it comes to concurrency—frankly, Twisted’s inlineCallbacks is simply not up to the job in terms of performance when it comes to many coroutines, and neither in terms of ease/transparency of use: yield and Deferreds everywhere; often hard to build some abstractions; horrifyingly useless stack traces with both bare Deferreds as well as, and even more so with @inlineCallbacks.
  • All the built-in functionality of Twisted you can ever dream of, including but not limited to IReactorProcess.spawnProcess.

I’m personally currently using Gevent 1.0rc2 with Twisted 12.3 bridged by geventreactor. I have implemented my own as-of-yet unpublished additions and enhancements to geventreactor which I will publish soon, hopefully as part of geventreactor‘s original GitHub repository: https://github.com/jyio/geventreactor.

My current layout allows me to program in the nice programming model of Gevent, and leverage things such as a non-blocking socket, urllib2 and other modules. I can use regular Python code for doing regular things, as opposed to the learning curve and inconvenience of doing even simple, basic things the Twisted way. I can also easily use most 3rd party libraries that are normally either out of question with Twisted, or require the use of threads.

I can also completely avoid the awkward and often overly complex callback based programming by using greenlets (instead of Deferreds and callbacks, and/or @inlineCallbacks).

(This answer was written based on my personal experiences having used both Twisted and Gevent in real life projects, with significantly more experience using Twisted (but I don’t claim to be a Twisted expert). The software I’ve had to write hasn’t had to use too many of Twisted’s features, so depending on the set of features you require of Twisted, the (relatively painless) extra complexity of mixing Gevent and Twisted might not be worth the trouble.)