【问题标题】:Using gevent with pyramid将 gevent 与金字塔一起使用
【发布时间】:2013-01-12 07:33:57
【问题描述】:

我正在使用金字塔构建网站,我想从其他网站获取一些数据。因为urlopen 可能有 50+ 次调用,所以我想使用 gevent 来加快速度。

这是我到目前为止使用 gevent 得到的结果:

import urllib2    
from gevent import monkey; monkey.patch_all()
from gevent import pool

gpool = gevent.pool.Pool()

def load_page(url):
    response = urllib2.urlopen(url)
    html = response.read()
    response.close()
    return html

def load_pages(urls):
    return gpool.map(load_page, urls)

运行pserve development.ini --reload 给出:

NotImplementedError: gevent is only usable from a single thread.

我已经读到我需要先进行猴子补丁,但我不确定在哪里合适。另外,这是特定于 pserve 的问题吗?当我搬到mod_wsgi 时,我需要重新解决这个问题吗?或者有没有办法在没有 gevent 的情况下处理这个用例(只是 urlopen)?我已经看到了针对 requests 的建议,但我在文档中找不到获取多个页面的示例。

更新 1:

我也试过this SO question的eventlet(几乎是直接从这个eventletexample复制过来的):

import eventlet
from eventlet.green import urllib2

def fetch(url):
    return urllib2.urlopen(url).read()

def fetch_multiple(urls):
    pool = eventlet.GreenPool()
    return pool.imap(fetch, urls)

但是,当我拨打fetch_multiple 时,我收到的是TypeError: request() got an unexpected keyword argument 'return_response'

更新 2:

上一次更新中的TypeError 可能来自之前尝试使用 gevent 进行猴子补丁并且未正确重新启动 pserve。一旦我重新启动一切,它就可以正常工作。经验教训。

【问题讨论】:

  • 对于您的eventlet 代码……get_html 来自哪里?
  • 抱歉,应该是fetch。已更新。
  • 好吧,我就是这么想的。无论如何,IIRC,eventlet 在这种情况下所做的是接管当前线程以运行 greenlets,直到池完成。我认为无论如何你最好分派到一个greenlet线程,即使这确实有效。但是,如果这可行,并且您想使用它,我想这可能是eventlet 对您而言优于gevent 的优势。
  • 对,我希望它能做到这一点,但我得到了request() got an unexpected keyword argument 'return_response'。我尝试添加一个 pool.waitall() 以防返回地图是问题,但没有运气。
  • 其实我只是尝试重新启动整个堆栈,效果很好。当 pserve 重新启动所有东西时,一定是猴子修补某个地方没有被清除,这一直是垃圾。感谢您的帮助!

标签: python pyramid gevent urlopen


【解决方案1】:

有多种方法可以做你想做的事:

  • 创建一个专用的 gevent 线程,并将所有打开 URL 的作业显式分派到该线程,然后该线程将执行已发送的 urlopen 请求。
  • 使用线程而不是greenlets。运行 50 个线程不会对任何现代操作系统造成负担。
  • 使用线程池和队列。一次下载 50 次而不是一次下载 8 次(就像您的浏览器可能那样)通常没有太大优势。
  • 使用不同的异步框架,而不是 gevent,它不能通过神奇地绿化您的代码来工作。
  • 使用具有自己的非魔法异步支持的库,例如 pycurl
  • 不要混合和匹配不兼容的框架,也可以围绕gevent 构建服务器,或者找到一些其他框架同时满足您的网络服务和网络客户端的需求。

您可以通过首先加载gevent 来模拟最后一个而不更改框架,然后让它对您的线程进行monkeypatch,强制您现有的线程服务器框架成为gevent 服务器。但这可能不起作用,或者大部分工作但偶尔会失败,或者工作但速度要慢得多......真的,使用设计为gevent-friendly(或至少greenlet-friendly)的框架是一个更好的主意,如果那是你想走的路。

您提到其他人推荐了requests。找不到文档的原因是 requests 中的内置异步代码已被删除。请参阅an older version,了解它的使用方式。它现在作为一个单独的库提供,grequests。但是,它通过将requestsgevent 隐式包装来工作,因此它会遇到与您自己这样做完全相同的问题。

(使用requests而不是urllib2还有其他原因,如果你想使用gevent,使用grequests比自己做更容易。)

【讨论】:

  • 我看过 grequests 但正如你提到的,同样的问题。我还查看了 eventlet,但我遇到了一个不寻常的错误(上面已编辑)。我可能会尝试创建一个专用的 gevent 线程...
  • @NumberOverZero:是的,我认为这可能是你今天最简单的路径(这就是我把它放在第一位的原因)。
【解决方案2】:

我在尝试部署 Web 应用程序时遇到了类似的 gevent 问题。您可以做的最省事的事情是使用在 gevent 上运行的 WSGI 部署;示例包括 gUnicorn、uWSGI 或 gevent 的内置 WSGI 服务器之一。 Pyramid 应该有一种使用备用部署的方法。如果您的大部分代码依赖于 gevent,那么只使用在 gevent 上运行的服务器会更容易。

所以,基本上是上述答案的最后一个项目符号。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    • 2014-02-01
    • 2015-01-08
    • 1970-01-01
    • 2021-11-28
    相关资源
    最近更新 更多