简体   繁体   English

从另一个线程关闭“Python请求”连接

[英]Closing “Python Requests” connection from another thread

To close the application as soon as possible, can I interrupt requests.post call from another thread and have it terminate connection immediately ? 要尽快关闭应用程序,我是否可以中断来自另一个线程的requests.post调用并立即终止连接?

I played with adapters, but no luck so far: 我玩适配器,但到目前为止没有运气:

for ad in self.client.session.adapters.values():
    ad.close()

The right way to do this is to use message passing into the other thread. 正确的方法是使用消息传递到另一个线程。 We can do a poor-mans version of this by using a shared global variable. 我们可以通过使用共享的全局变量来做一个穷人版本。 As an example, you can try running this script: 例如,您可以尝试运行此脚本:

#!/usr/bin/env python
# A test script to verify that you can abort streaming downloads of large
# files.
import threading
import time
import requests

stop_download = False

def download(url):
    r = requests.get(url, stream=True)
    data = ''
    content_gen = r.iter_content()

    while (stop_download == False):
        try:
            data = r.iter_content(1024)
        except StopIteration:
            break

    if (stop_download == True):
        print 'Killed from other thread!'
        r.close()

if __name__ == '__main__':
    t = threading.Thread(target=download, 
                         args=('http://ftp.freebsd.org/pub/FreeBSD/ISO-IMAGES-amd64/9.1/FreeBSD-9.1-RELEASE-amd64-dvd1.iso',)
                        ).start()
    time.sleep(5)
    stop_download = True
    time.sleep(5) # Just to make sure you believe that the message actually stopped the other thread.

When doing this in production, especially if you don't have the protection of the GIL, you will want to use more caution around the message-passing state to avoid awkward multithreading bugs. 在生产中执行此操作时,尤其是如果您没有GIL的保护,您将需要在消息传递状态周围使用更多的警告,以避免尴尬的多线程错误。 I'm leaving that up to the implementor. 我把它留给了实现者。

I found a way, here is how to interrupt connection 我找到了一种方法,这里是如何中断连接

def close():
    time.sleep(5)
    r.raw._fp.close()

t = threading.Thread(target=close).start()
print "getting"
s = requests.Session()
r = s.get("http://download.thinkbroadband.com/1GB.zip", stream = True)
for line in r.iter_content(1024):
    log.debug("got it: %s", len(line))
print "done"

However it is a hack and I don't like it, private members can change in the future, I am returning to urllib2 然而,这是一个黑客,我不喜欢它,私人成员可以在将来改变,我回到urllib2

So if you do the following from the interactive shell, you'll see that closing the adapters doesn't appear to do what you're looking for. 因此,如果您从交互式shell执行以下操作,您将看到关闭适配器似乎无法执行您要查找的内容。

import requests
s = requests.session()
s.close()
s.get('http://httpbin.org/get')
<Response [200]>
for _, adapter in s.adapters.items():
    adapter.close()

s.get('http://httpbin.org/get')
<Response [200]>
s.get('https://httpbin.org/get')
<Response [200]>

This looks like it may be a bug in requests, but in general, closing the adapter should prevent you from making further requests but I'm not entirely sure it will interrupt currently running requests. 这似乎可能是请求中的错误,但一般情况下,关闭适配器应该阻止您进一步请求,但我不完全确定它会中断当前正在运行的请求。

Looking at HTTPAdapter (which powers both the standard 'http://' and 'https://' adapters), calling close on it will call clear on the underlying urrllib3 PoolManager. 查看HTTPAdapter(为标准的'http://''https://'适配器提供支持),在其上调用close将在底层urrllib3 PoolManager上调用clear From urllib3's documentation of that method you see that: 从urllib3的该方法文档中你可以看到:

This will not affect in-flight connections, but they will not be
re-used after completion.

So in essence, you see that you cannot affect a connection that has not yet completed. 所以从本质上讲,您会发现不能影响尚未完成的连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM