urlopen/requests.get 无法在导入模块中创建的线程中工作

urlopen/requests.get not working in threads created in imported modules

我对 urlopen 有疑问 (和 requests.get)

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

"won't run" 我的意思是甚至没有开始:超时(这里是 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 上编写的代码按预期工作(即 "Before request/After request/End of program"),我还不能用简化的代码重现问题。

我仍在尝试,但与此同时我想知道是否有人遇到过这种奇怪的行为以及可能导致这种行为的原因。请注意,如果我不使用线程,一切都很好。

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

更新

重现该行为的方法如下

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

现在我找到了重现的方法:这种行为正常吗?预期?

我怎样才能摆脱它? IE。从导入的模块创建一个线程,使 urlopen 按预期加载。

你的代码没问题。预计单次发射。

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

我忘了 post 解决方案,感谢 @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')

这样事情*就不再阻塞,一切都按预期进行。