【问题标题】:pycurl/curl not following the CURLOPT_TIMEOUT optionpycurl/curl 不遵循 CURLOPT_TIMEOUT 选项
【发布时间】:2011-05-31 18:33:27
【问题描述】:

我有一个多线程脚本,当它连接到服务器时偶尔会冻结,但服务器没有发回任何内容。 Netstat 显示一个连接的 tcp 套接字。即使我设置了 TIMEOUT,也会发生这种情况。超时在非线程脚本中工作正常。这是一些示例代码。

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()

任何帮助将不胜感激!几周以来一直在尝试解决这个问题。

编辑: urllist 有大约 10 个 url。有多少似乎并不重要。

编辑2: 我刚刚在下面测试了这段代码。我使用了一个休眠 100 秒的 php 脚本。

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 似乎正确超时。所以我想这与网址的数量有关?吉尔?

编辑3:

我认为这可能与 libcurl 本身有关,因为有时当我检查脚本时,libcurl 仍然连续数小时连接到服务器。如果 pycurl 正确超时,则套接字将被关闭。

【问题讨论】:

  • 出现此问题时,urllist中有多少个url?只有一个(或几个)网址/线程仍然会发生这种情况吗?
  • 如果您使用“edit2”代码启动多个线程,它们是否都正确超时?
  • 是的,它们工作正常。用几百个生成的线程进行了尝试,所有线程都正常超时。

标签: python multithreading timeout pycurl


【解决方案1】:

Python 线程在某些情况下会受到全局解释器锁(“GIL”)的阻碍。可能是您启动的线程没有超时,因为它们实际上运行的频率不够高。

related StackOverflow question 可能会为您指明正确的方向:

【讨论】:

  • 据我了解,GIL 仅影响 python 代码。我理解 pycurl 只是将所有内容交给 libcurl,它自己处理超时。
  • GIL 确实会影响 Python 线程。检查相关问题。
  • 有些 url 需要 cookie,所以我不能使用 cookielib。否则我会坚持使用 urllib2。
  • 您能否详细说明“您正在启动的线程没有超时,因为它们实际上运行的频率不够高”?
  • GIL 不影响本机库调用,包括所有低级网络阻塞,因为本机库调用在等待时释放 GIL。 (一些错误的库不能正确执行此操作,例如。我记得 PIL 遇到了问题,但我希望 curl 能够处理它。)
【解决方案2】:

我修改了您的“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 和线程争用 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多