我正在尋找中止/取消 Python 線程中的 HTTP 請求。我必須堅持使用線程。我無法使用 asyncio 或標準庫之外的任何內容。此代碼適用于套接字:"""Demo for Canceling IO by Closing the SocketWorks!"""import socketimport timefrom concurrent import futuresstart_time = time.time()sock = socket.socket()def read(): "Read data with 10 second delay." sock.connect(('httpbin.org', 80)) sock.sendall(b'GET /delay/10 HTTP/1.0\r\n\r\n') while True: data = sock.recv(1024) if not data: break print(data.decode(), end='')with futures.ThreadPoolExecutor() as pool: future = pool.submit(read) futures.wait([future], timeout=5) sock.close() # <-- Interrupt sock.recv(1024) in Thread:read().end_time = time.time()print(f'Duration: {end_time - start_time:.3f}')# Duration is ~5s as expected.在主線程中關閉套接字用于中斷執行器池線程中的recv()。HTTP 請求應該需要 10 秒,但我們只等待 5 秒,然后關閉套接字(有效地取消 HTTP 請求/響應)?,F在我嘗試使用 http.client:"""Demo for Canceling IO in Threads with HTTP ClientDoesn't work!"""import timefrom concurrent import futuresfrom http.client import HTTPConnectiondef get(con, url): con.request('GET', url) response = con.getresponse() return responsestart_time = time.time()with futures.ThreadPoolExecutor() as executor: con = HTTPConnection('httpbin.org') future = executor.submit(get, con, '/delay/10') done, not_done = futures.wait([future], timeout=5) con.sock.close()end_time = time.time()print(f'Duration: {end_time - start_time:.3f}')# Duration is ~10s unfortunately.不幸的是,這里的總持續時間約為 10 秒。關閉套接字不會中斷客戶端中的recv_into()??磥砦易龀隽艘恍╁e誤的假設。如何從單獨的線程中斷 http 客戶端中使用的套接字?
1 回答

DIEA
TA貢獻1820條經驗 獲得超2個贊
您所描述的是預期的有據可查的行為:
注意 close() 釋放與連接關聯的資源,但不一定立即關閉連接。如果要及時關閉連接,請在 close() 之前調用 shutdown()。
有關此行為的一些進一步詳細信息仍然可以在 CPython howto 文檔中找到:
嚴格來說,您應該在關閉套接字之前對其使用 shutdown 。關閉是對另一端套接字的建議。根據您傳遞的參數,它可能意味著“我不會再發送,但我仍然會聽”,或者“我不聽,很好的擺脫!”。然而,大多數套接字庫已經習慣了程序員忽略使用這一禮儀,通常關閉與 shutdown() 相同;關閉()。因此在大多數情況下,不需要顯式關閉。
有效使用 shutdown 的一種方法是使用類似 HTTP 的交換??蛻舳税l送請求,然后執行關閉(1)。這告訴服務器“該客戶端已完成發送,但仍然可以接收。” 服務器可以通過接收 0 字節來檢測“EOF”。它可以假設它具有完整的請求。服務器發送回復。如果發送成功完成,那么客戶端確實仍在接收。
Python 在自動關閉方面更進了一步,它表示當套接字被垃圾回收時,如果需要它會自動關閉。但依賴這一點是一個非常不好的習慣。如果您的套接字在沒有執行關閉的情況下就消失了,另一端的套接字可能會無限期地掛起,認為您只是速度慢。完成后請關閉套接字。
解決方案
關閉之前調用 shutdown。
例子
with futures.ThreadPoolExecutor() as executor: con = HTTPConnection('httpbin.org') future = executor.submit(get, con, '/delay/10') done, not_done = futures.wait([future], timeout=5) con.sock.shutdown() con.sock.close()
添加回答
舉報
0/150
提交
取消