首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >绿叶大战。线程

绿叶大战。线程
EN

Stack Overflow用户
提问于 2013-03-21 19:49:46
回答 4查看 49.1K关注 0票数 153

我对gevents和greenlets都很陌生。我找到了一些关于如何使用它们的很好的文档,但是没有一个文件给我提供了如何和何时使用绿色环保的理由!

  • 他们到底擅长什么?
  • 在代理服务器中使用它们是个好主意吗?
  • 为什么不穿线?

我不确定的是,如果它们基本上是共同例程的话,它们如何才能为我们提供并发。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-03-24 07:47:32

Greenlet提供并发性,但不提供并行性。并发性是指代码可以独立于其他代码运行的时候。并行性是并发代码的同时执行。当用户空间中有大量工作要做时,并行性尤其有用,而这通常是CPU密集型的工作。并发性对于分解问题非常有用,可以更容易地并行调度和管理不同的部分。

Greenlet在网络编程中非常出色,在这种情况下,与一个套接字的交互可以独立于与其他套接字的交互。这是一个典型的并发性示例。因为每个greenlet都在自己的上下文中运行,所以您可以继续使用同步API而不需要线程处理。这是很好的,因为线程在虚拟内存和内核开销方面非常昂贵,所以您可以与线程实现的并发性要小得多。此外,由于GIL的缘故,Python中的线程比通常更昂贵和更有限。并发性的替代方案通常是Twisted、libevent、libuv、node.js等项目,在这些项目中,所有代码共享相同的执行上下文,并注册事件处理程序。

使用greenlets (通过gevent等适当的网络支持)编写代理是一个很好的主意,因为您对请求的处理能够独立执行,并且应该按此方式编写。

Greenlet提供并发性是因为我之前给出的原因。并发性不是并行性。通过隐藏事件注册并在通常会阻塞当前线程的调用中为您执行调度,像gevent这样的项目无需更改异步API而公开此并发性,并且对系统的成本要低得多。

票数 222
EN

Stack Overflow用户

发布于 2018-08-20 14:02:01

更正@TemporalBeing上面的答案,绿线并不比线程“快”,而且生成60000线程以解决并发问题是一种错误的编程技术,相反,一小部分线程池是合适的。下面是一个更合理的比较(来自我的reddit邮报,回应引用这么多帖子的人)。

代码语言:javascript
复制
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)

以下是一些结果:

代码语言:javascript
复制
--------------------
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代码能够处理的数千个连接要快得多。

票数 20
EN

Stack Overflow用户

发布于 2015-03-06 21:16:18

使用@Max的答案,并添加一些相关性,以进行缩放,您可以看到差异。为此,我更改了要填充的URL,如下所示:

代码语言:javascript
复制
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次迭代中:

代码语言:javascript
复制
Using gevent it took: 3.756914
-----------
Using multi-threading it took: 15.797028

因此,您可以看到,在使用gevent的I/O方面有一些显著的差异。

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15556718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档