urlopen / requests.get在导入的模块

时间:2016-04-04 15:06:35

标签: python multithreading python-requests urllib2 urlopen

我的urlopen有问题 (和requests.get)

在我的程序中,如果我在一个线程中运行它(我也用multiprocessing进行了测试)[更新:一个由导入的模块创建的线程]它将一直运行直到程序结束

通过"赢了"运行"我的意思是甚至没有开始:超时(这里是3秒)永远不会触发,并且网站上有没有连接。

这是我的简化代码:

import threading,urllib2,time

def dlfile(url):
  print 'Before request'
  r = urllib2.urlopen(url, timeout=3)
  print 'After request'
  return r

def dlfiles(*urls):
  threads = [threading.Thread(None, dlfile, None, (url,), {}) for url in urls]
  map(lambda t:t.start(), threads)

def main():
    dlfiles('http://google.com')

main()
time.sleep(10)
print 'End of program'

我的输出:

Before request
End of program
After request

不幸的是,我在SO上写的代码按预期工作(即"请求之前/请求之后/程序结束")我无法重现问题还有简化的代码。

我还在努力,但在此期间,我想知道是否有人遇到过这种奇怪的行为以及可能导致这种行为的原因。请注意,如果我不使用线程,那么一切都很好。

感谢您提供的任何帮助,我有点迷失,甚至互联网都不知道这个

更新

以下是如何重现行为

threadtest.py

import threading,urllib2,time
def log(a):print(a)
def dlfile(url):
  log('Before request')
  r = urllib2.urlopen(url, timeout=3)
  log('After request')
  return r

def dlfiles(*urls):
  threads = [threading.Thread(None, dlfile, None, (url,), {}) for url in urls]
  map(lambda t:t.start(), threads)

def main():
    dlfiles('http://google.com')

main()
for i in range(5):
    time.sleep(1)
    log('Sleep')
log('End of program')

threadtest-import.py

import threadtest

然后输出将是:

$ python threadtest.py
Before request
After request
Sleep
Sleep
Sleep
Sleep
Sleep
End of program

$ python threadtest-import.py
Before request
Sleep
Sleep
Sleep
Sleep
Sleep
End of program
After request

现在我发现了如何重现:这种行为是正常的吗?预期?

我怎么能摆脱它?即从导入的模块创建一个可以按预期加载urlopen的线程。

2 个答案:

答案 0 :(得分:1)

你的代码很好。预计单次发布。

def main():
    dlfiles('http://google.fr')

您在这里传递单url

threads = [threading.Thread(None, dlfile, None, (url,), {}) for url in urls]

列表理解只会产生一个线程,因为urls中有单个元素。

尝试:

def main():
    dlfiles('http://google.fr', 'http://google.com', 'http://google.gg')

答案 1 :(得分:0)

我忘了发布解决方案,感谢@ user3351750的评论。

问题是文件的结构。在threadtest-import.py中我导入threadtest,在导入模块的过程中,*(我不记得确切的机制)变成了阻塞。 IIRC这与urllib中的re模块有关。 很抱歉不清楚。

修复方法是将代码放入函数内的导入模块中。这是一个很好的做法,我猜是有原因的。

即。这样做:

import threadtest #do nothing except declarations
threadtest.run() #do the work

而不是:

import threadtest #declarations + work

并输入代码

main()
for i in range(5):
    time.sleep(1)
    log('Sleep')
log('End of program')

run函数内:

def run():
    main()
    for i in range(5):
        time.sleep(1)
        log('Sleep')
    log('End of program')

这样东西*就会停止阻塞,一切都按预期工作。