pycurl/curl未遵循CURLOPT_TIMEOUT选项
我有一个多线程的脚本,有时候在连接到服务器时会卡住,但服务器没有发送任何数据。用Netstat查看时,显示有一个连接的tcp套接字。即使我设置了超时,这种情况也会发生。在没有线程的脚本中,超时设置是正常工作的。这是一些示例代码。
def xmlscraper(url):
htmlpage = StringIO.StringIO()
rheader = StringIO.StringIO()
c = pycurl.Curl()
c.setopt(pycurl.USERAGENT, "user agent string")
c.setopt(pycurl.CONNECTTIMEOUT, 60)
c.setopt(pycurl.TIMEOUT, 120)
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.setopt(pycurl.WRITEFUNCTION, htmlpage.write)
c.setopt(pycurl.HEADERFUNCTION, rheader.write)
c.setopt(pycurl.HTTPHEADER, ['Expect:'])
c.setopt(pycurl.NOSIGNAL, 1)
c.setopt(pycurl.URL, url)
c.setopt(pycurl.HTTPGET, 1)
pycurl.global_init(pycurl.GLOBAL_ALL)
for url in urllist:
t = threading.Thread(target=xmlscraper, args=(url,))
t.start()
如果有人能帮忙,我会非常感激!我已经尝试解决这个问题好几个星期了。
补充说明:
这个url列表大约有10个网址。似乎网址的数量并不重要。
补充说明2:
我刚刚测试了下面的代码。我用了一个php脚本,让它睡眠100秒。
import threading
import pycurl
def testf():
c = pycurl.Curl()
c.setopt(pycurl.CONNECTTIMEOUT, 3)
c.setopt(pycurl.TIMEOUT, 6)
c.setopt(pycurl.NOSIGNAL, 1)
c.setopt(pycurl.URL, 'http://xxx.xxx.xxx.xxx/test.php')
c.setopt(pycurl.HTTPGET, 1)
c.perform()
t = threading.Thread(target=testf)
t.start()
t.join()
在那段代码中,pycurl似乎能正常超时。所以我猜这可能和网址的数量有关?或者是GIL的问题?
补充说明3:
我觉得这可能和libcurl本身有关,因为有时候我检查脚本时,libcurl仍然连接着一个服务器,持续好几个小时。如果pycurl能正常超时,那么套接字应该早就关闭了。
2 个回答
1
在某些情况下,Python 的线程会受到一个叫做全局解释器锁(GIL)的限制。这意味着你启动的线程可能没有超时,是因为它们实际上没有被频繁地运行。
这个 相关的 StackOverflow 问题 可能会给你一些有用的提示:
3
我把你的'edit2'代码改了一下,让它可以同时运行多个线程,在我的电脑上(Ubuntu 10.10,Python 2.6.6)运行得很好。
import threading
import pycurl
def testf():
c = pycurl.Curl()
c.setopt(pycurl.CONNECTTIMEOUT, 3)
c.setopt(pycurl.TIMEOUT, 3)
c.setopt(pycurl.NOSIGNAL, 1)
c.setopt(pycurl.URL, 'http://localhost/cgi-bin/foo.py')
c.setopt(pycurl.HTTPGET, 1)
c.perform()
for i in range(100):
t = threading.Thread(target=testf)
t.start()
我可以启动100个线程,所有线程在3秒后超时(就像我设定的那样)。
我觉得还不需要去怪罪全局解释器锁(GIL)和线程竞争的问题呢 :)