Python 正确的greenlet终止

Python 正确的greenlet终止,python,gevent,greenlets,Python,Gevent,Greenlets,我正在使用gevent下载一些html页面。 有些网站速度太慢,有些网站在一段时间后停止服务请求。这就是为什么我必须限制一组请求的总时间。为此,我使用gevent“Timeout” 但它的问题是,当异常触发时,我失去了所有状态 想象一下我在“www.test.com”上爬行。在站点管理员决定切换Web服务器进行维护之前,我已经下载了10个URL。在这种情况下,当异常触发时,我将丢失有关已爬网页面的信息 问题是-即使发生超时,我如何保存状态和处理数据?为什么不尝试以下方法: timeout = T

我正在使用gevent下载一些html页面。 有些网站速度太慢,有些网站在一段时间后停止服务请求。这就是为什么我必须限制一组请求的总时间。为此,我使用gevent“Timeout”

但它的问题是,当异常触发时,我失去了所有状态

想象一下我在“www.test.com”上爬行。在站点管理员决定切换Web服务器进行维护之前,我已经下载了10个URL。在这种情况下,当异常触发时,我将丢失有关已爬网页面的信息


问题是-即使发生超时,我如何保存状态和处理数据?

为什么不尝试以下方法:

timeout = Timeout(10)

def downloadSite(url):
    with Timeout(10):
        downloadUrl(url)

urls = ["url1", "url2", "url3"]

workers = []
limit = 5
counter = 0
for i in urls:
    # limit to 5 URL requests at a time
    if counter < limit:
        workers.append(gevent.spawn(downloadSite, i))
        counter += 1
    else:
        gevent.joinall(workers)
        workers = [i,]
        counter = 0
gevent.joinall(workers)
timeout=超时(10)
def下载站点(url):
带超时(10):
下载url(url)
URL=[“url1”、“url2”、“url3”]
工人=[]
极限=5
计数器=0
对于URL中的i:
#一次最多5个URL请求
如果计数器<极限:
附加(gevent.spawn(下载站点,i))
计数器+=1
其他:
gevent.joinall(工人)
工人=[i,]
计数器=0
gevent.joinall(工人)

您还可以将每个URL的状态保存在dict或其他文件中,或将失败的URL追加到其他数组中,以便稍后重试。

一个自包含的示例:

import gevent
from gevent import monkey
from gevent import Timeout

gevent.monkey.patch_all()
import urllib2

def get_source(url):
    req = urllib2.Request(url)
    data = None
    with Timeout(2):
        response = urllib2.urlopen(req)
        data = response.read()
    return data

N = 10
urls = ['http://google.com' for _ in xrange(N)]
getlets = [gevent.spawn(get_source, url) for url in urls]
gevent.joinall(getlets)
contents = [g.get() for g in getlets]

print contents[5]
它为每个请求实现一个超时。在本例中,
contents
包含的HTML源代码是google.com的10倍,每一个都是在一个独立的请求中检索到的。如果其中一个请求超时,则
内容
中的相应元素将为
。如果您对此代码有任何疑问,请在评论中询问

我看到了你最后的评论。从编程的角度来看,为每个请求定义一个超时肯定没有错。如果你需要限制网站的流量,那就不要同时产生100个greenlet。产卵5号,等他们回来。然后,您可以等待给定的时间量,然后生成下一个5(已经在Gabriel Samfira的另一个答案中显示,正如我现在看到的)。对于我上面的代码,这意味着您必须反复调用

N = 10
urls = ['http://google.com' for _ in xrange(N)]
getlets = [gevent.spawn(get_source, url) for url in urls]
gevent.joinall(getlets)
contents = [g.get() for g in getlets]

然而
N
不应该太高。

为什么不为每个请求定义一个超时?downloadUrl()实际上在做什么?它是合作阻塞吗?你能提供一个独立的例子吗?代码被简化了。函数包含获取首页、查找好的内部链接、下载它们、查找更多链接等的代码。。。我无法想象如何将每个请求包装在一个单独的超时中。从编程的角度来看,这是错误的,它将对网站产生重大影响(想象一下同时从“www.test.com”请求100个网页)谢谢你,Gabriel,这很有效。我是python新手,不知道“with”构造:)谢谢Jan Philip!我之所以接受Gabriel的答案,仅仅是因为第一个提到“with Timeout(10):”构造,尽管代码基本相似。(再次感谢)
N = 10
urls = ['http://google.com' for _ in xrange(N)]
getlets = [gevent.spawn(get_source, url) for url in urls]
gevent.joinall(getlets)
contents = [g.get() for g in getlets]