当没有数据时,是否可以阻止python的http.client.HTTPResponse.read()挂起?

时间:2015-02-09 00:02:02

标签: python multithreading twitter

我正在使用Python http.client.HTTPResponse.read()从流中读取数据。也就是说,服务器会永久保持连接打开,并在数据可用时定期发送数据。没有预期的响应时间。特别是,我正在通过Twitter Streaming API获取推文。

为了做到这一点,我反复调用http.client.HTTPResponse.read(1)来获得响应,一次一个字节。问题是,如果没有要读取的数据,程序将挂在该行上,这段时间不存在(当没有推文进入时)。

我正在寻找一种能够获得HTTP响应的单个字节的方法(如果可用),但如果没有要读取的数据,则会立即失败。

read that you can set a timeout when the connection is created,但是在连接上设置超时会使其长时间保持打开等待数据进入的目的失败。我不想设置超时,我想要如果有数据需要读取,则读取数据;如果没有,则读取数据,如果没有等待,则读取数据。

我想用我现在所拥有的(使用http.client)来做这件事,但如果绝对必要我使用不同的库来执行此操作,那么就这样吧。我试图完全自己写这个,所以建议我使用别人已经编写的Python的Twitter API并不是我想要的。

此代码获取响应,它在主要的单独的线程中运行:

while True:
    try:
        readByte = dc.request.read(1)
    except:
        readByte = []

    if len(byte) != 0:
        dc.responseLock.acquire()
        dc.response = dc.response + chr(byte[0])
        dc.responseLock.release()

请注意,请求存储在dc.request中,而dc.response中的响应存储在其他位置。 dc.responseLockLock,可防止多个线程同时访问dc.response

在单独的线程上运行时,主线程可以获得dc.response,其中包含到目前为止收到的整个响应。新数据会在不阻塞主线程的情况下添加到dc.response

这在运行时效果很好,但是当我希望停止时遇到问题。我将while语句更改为while not dc.twitterAbort,因此当我想中止此线程时,我只需将dc.twitterAbort设置为True,线程就会停止。

但事实并非如此。此线程在此之后会保留很长时间,卡在dc.request.read(1)部分。必须有某种超时,因为它最终会返回到while语句并停止该线程,但这需要大约10秒才能实现。

如果我的帖子停留在read()的调用上,怎么能让我的帖子立即停止?

同样,此方法正在努力获取推文,问题仅在于将其设置为停止。如果我以完全错误的方式解决这个问题,请随意指出我正确的方向。我是Python的新手,所以我可能会忽略一些更简单的方法。

1 个答案:

答案 0 :(得分:1)

您的想法并不新鲜,有一些操作系统机制(*)可确保应用程序在确保不阻塞时仅调用与I / O相关的系统调用。这些机制通常由异步I / O框架使用,例如龙卷风或gevent。使用其中之一,您会发现运行代码很容易#34;而#34;您的应用程序正在等待I / O事件,例如等待套接字上的传入数据。

如果您使用gevent的猴子修补方法,则可以按要求继续使用http.client。您只需要习惯gevent / greenlets引入的协作调度范例,其中您的执行流程会跳过"跳过"在子程序之间。

当然,您也可以在另一个线程中执行阻塞I / O(就​​像您一样),这样它就不会影响主线程的响应能力。关于你的"如何让我的帖子立即停止" 问题:

  • 强制在系统调用中阻塞的线程停止通常不是一个干净甚至有效的过程(另请参阅Is there any way to kill a Thread in Python?)。要么 - 如果你的应用程序已经完成了它的工作 - 你取消了整个过程,这也影响了所有包含的线程,或者你只是留下线程并给它足够的时间根据需要终止(你引用的这10秒)不是问题 - 是吗?)

  • 如果您不希望在应用程序的任何位置进行长时间阻塞系统调用(无论是否在主线程中),请使用上述技术来阻止系统调用。

(*)参见例如http://man7.org/linux/man-pages/man2/open.2.html

中的O_NONBLOCK选项