2015-02-09 46 views
3

我正在使用Python http.client.HTTPResponse.read()從流中讀取數據。也就是說,服務器永遠保持連接打開,並在數據可用時定期發送數據。沒有預期的響應時間。特別是,我通過Twitter Streaming API收到推文。當沒有數據時,是否可以阻止python的http.client.HTTPResponse.read()掛起?

爲了達到這個目的,我一再呼叫http.client.HTTPResponse.read(1)得到響應,一次一個字節。問題在於,如果沒有要讀取的數據,程序將掛在該行上,而這段時間並不是很長時間(當沒有Tweets進入時)。

我正在尋找一種方法,將獲得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.requestdc.response響應,這些在別處創建。 dc.responseLock是一個Lock,它可以防止dc.response一次被多個線程訪問。

由於它在單獨的線程上運行,因此主線程可以獲得dc.response,其中包含到目前爲止收到的全部響應。新數據在不阻塞主線程的情況下被添加到dc.response

這完美的作品時,它的運行,但我遇到一個問題時,我希望它停止。我改變了我的while語句爲while not dc.twitterAbort,所以當我想中止這個線程時,我只是將dc.twitterAbort設置爲True,並且線程將停止。

但它沒有。此線程在此之後很長一段時間,堅持在dc.request.read(1)部分。必須有某種超時,因爲它最終會返回到while語句並停止該線程,但發生這種情況大約需要10秒。

如何在我想要的時候讓我的線程立即停止,如果它卡在read()的電話上?

同樣,這種方法正在得到鳴叫,問題只在它前往停止。如果我以完全錯誤的方式回答這個問題,請隨時指出我的方向。我是Python的新手,所以我可能忽略了一些更簡單的方法來解決這個問題。

回答

1

您的想法並不新鮮,有確保應用程序只在調用I/O相關係統調用時確保爲不會阻止的操作系統機制(*)。這些機制通常由異步I/O框架使用,例如龍捲風或gevent。使用其中之一,並且您會發現運行代碼非常容易,「而」您的應用程序正在等待I/O事件,例如等待套接字上的傳入數據。

如果您使用gevent的猴子修補方法,則可以按照要求繼續使用http.client。您只需要習慣gevent/greenlets引入的協作式調度範例,其中您的執行流程在子例程之間「跳躍」。

當然,您也可以在另一個線程中執行阻塞I/O(就​​像您一樣),這樣它就不會影響主線程的響應。關於你「我怎樣才能讓我的線程立即停止」問題:

  • 強制該用戶的屏蔽在系統調用來停止一個線程通常是不乾淨的,甚至有效的方法(也見Is there any way to kill a Thread in Python?)。要麼 - 如果你的應用程序已經完成了它的工作 - 你把整個過程取下來,這也會影響到所有包含的線程,或者你只需​​要把線程留下來,並給它足夠多的時間根據需要終止(這10秒不是問題 - 他們是嗎?)

  • 如果你不想在你的應用程序中的任何地方(不管是否在主線程中)使用這種長時間阻塞的系統調用,那麼使用上述技術以防止阻止系統調用。

(*)參見例如, O_NONBLOCK選項http://man7.org/linux/man-pages/man2/open.2.html

相關問題