Eventlet的spawn无法工作,真奇怪
**** 大家好
我正在用eventlet来做一个网页爬虫。我的代码大致是这样的
import eventlet
urls = [
"http://deeplearning.stanford.edu/wiki/index.php/UFLDL%E6%95%99%E7%A8%8B",
"http://www.google.com.hk",
"http://www.baidu.com",
]
def fetch(url):
print('entering fetch')
body=urllib2.urlopen(url).read()
print('body')
pool = eventlet.GreenPool(100)
for url in urls:
pool.spawn(fetch,url)
time.sleep(10)
但是它什么都没有输出,似乎fetch根本没有运行
顺便说一下,pool.imap是可以工作的
这是怎么回事呢?
我想做的是:这些网址是一个接一个地过来的,就像这样
While(True):
url=getOneUrl() #get one url streamly
pool.spawn(fetch,url) #fetch the url
但是这个也不行。
提前谢谢大家……
2 个回答
你可以看看我用 Eventlet 写的爬虫:https://github.com/temoto/heroshi/blob/3b5e273783de9ea4b24cbcb0bf01a5025f653b93/heroshi/worker/Crawler.py
你得到了 Yuan 的很棒的回复,我只想补充两点:
time.sleep()
如果不进行猴子补丁,会导致整个程序停住,这样就无法获取任何网址。你可以在开始时运行eventlet.monkey_patch()
,或者使用eventlet.sleep()
。关于流式网址,你可能想直接使用 Heroshi 主程序中的 io-worker。它是一个独立的程序,可以从标准输入读取网址,爬取这些网址,然后把结果写到标准输出。如果你真的想用 Eventlet 来做这个,可以使用共享队列,这样是可行的:
pool = eventlet.GreenPool(100)
urls = eventlet.queue.Queue()
results = eventlet.queue.Queue()
urls.put('http://seed-url-1')
urls.put('http://seed-url-2')
# ...
def fetch(url):
# ...
results.put(...)
def crawl():
while True: # this is not C/Java, you don't need parens
url = urls.get()
pool.spawn(fetch, url)
def parse():
while True:
result = results.get()
# ...
urls.put(new_url_from_page)
eventlet.spawn(crawl)
eventlet.spawn(parse)
根据eventlet的实现,pool.imap这段代码会等到池里的所有绿色线程(greenthreads)都完成工作后才会继续,但pool.spawn则不会,它会立即结束。
你可以试着在脚本的最后加一些等待或者睡眠的代码。这样那些被创建的绿色线程就会执行你的函数。
pool.waitall()
或者
eventlet.sleep(10)
其实,在'for body in pool.imap(fetch, urls)'这段代码中,它调用了pool.imap并迭代结果。pool.imap的调用本身并不会等待,但迭代过程会。
试着不迭代结果,这样就会像pool.spawn一样,立即结束。
pool = eventlet.GreenPool(100)
pool.imap(fetch, urls)
如果你想了解更多,可以查看greenpool.py里的代码。
所有的绿色线程其实只有一个线程在运行。你在所有绿色线程上试一下,你会得到一个唯一的线程ID。
print greenthread.getcurrent(), threading.current_thread()
如果在没有eventlet.sleep的情况下循环,线程会一直被阻塞。其他的绿色线程就没有机会被调度。所以解决你问题的一个可能方法是在你的while循环中调用spawn后加上eventlet.sleep。