Eventlet的spawn无法工作,真奇怪

1 投票
2 回答
1408 浏览
提问于 2025-04-18 13:08

**** 大家好

我正在用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 个回答

0

你可以看看我用 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)
1

根据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。

撰写回答