自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何用最快的方式發(fā)送 10 萬個 HTTP 請求

開發(fā) 架構(gòu)
假如有一個文件,里面有 10 萬個 url,需要對每個 url 發(fā)送 http 請求,并打印請求結(jié)果的狀態(tài)碼,如何編寫代碼盡可能快的完成這些任務呢?

[[419539]]

假如有一個文件,里面有 10 萬個 url,需要對每個 url 發(fā)送 http 請求,并打印請求結(jié)果的狀態(tài)碼,如何編寫代碼盡可能快的完成這些任務呢?

Python 并發(fā)編程有很多方法,多線程的標準庫 threading,concurrency,協(xié)程 asyncio,當然還有 grequests 這種異步庫,每一個都可以實現(xiàn)上述需求,下面一一用代碼實現(xiàn)一下,本文的代碼可以直接運行,給你以后的并發(fā)編程作為參考:

隊列+多線程

定義一個大小為 400 的隊列,然后開啟 200 個線程,每個線程都是不斷的從隊列中獲取 url 并訪問。

主線程讀取文件中的 url 放入隊列中,然后等待隊列中所有的元素都被接收和處理完畢。代碼如下:

  1. from threading import Thread 
  2. import sys 
  3. from queue import Queue 
  4. import requests 
  5.  
  6. concurrent = 200 
  7.  
  8.  
  9. def doWork(): 
  10.     while True
  11.         url = q.get() 
  12.         status, url = getStatus(url) 
  13.         doSomethingWithResult(status, url) 
  14.         q.task_done() 
  15.  
  16.  
  17. def getStatus(ourl): 
  18.     try: 
  19.         res = requests.get(ourl) 
  20.         return res.status_code, ourl 
  21.     except
  22.         return "error", ourl 
  23.  
  24.  
  25. def doSomethingWithResult(status, url): 
  26.     print(status, url) 
  27.  
  28.  
  29. q = Queue(concurrent * 2) 
  30. for i in range(concurrent): 
  31.     t = Thread(target=doWork) 
  32.     t.daemon = True 
  33.     t.start() 
  34.  
  35. try: 
  36.     for url in open("urllist.txt"): 
  37.         q.put(url.strip()) 
  38.     q.join() 
  39. except KeyboardInterrupt: 
  40.     sys.exit(1) 

運行結(jié)果如下:

有沒有 get 到新技能?

線程池

如果你使用線程池,推薦使用更高級的 concurrent.futures 庫:

  1. import concurrent.futures 
  2. import requests 
  3.  
  4. out = [] 
  5. CONNECTIONS = 100 
  6. TIMEOUT = 5 
  7.  
  8. urls = [] 
  9. with open("urllist.txt"as reader: 
  10.     for url in reader: 
  11.         urls.append(url.strip()) 
  12.  
  13. def load_url(url, timeout): 
  14.     ans = requests.get(url, timeout=timeout) 
  15.     return ans.status_code 
  16.  
  17. with concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS) as executor: 
  18.     future_to_url = (executor.submit(load_url, url, TIMEOUT) for url in urls) 
  19.     for future in concurrent.futures.as_completed(future_to_url): 
  20.         try: 
  21.             data = future.result() 
  22.         except Exception as exc: 
  23.             data = str(type(exc)) 
  24.         finally: 
  25.             out.append(data) 
  26.             print(data) 

協(xié)程 + aiohttp

協(xié)程也是并發(fā)非常常用的工具了:

  1. import asyncio 
  2. from aiohttp import ClientSession, ClientConnectorError 
  3.  
  4. async def fetch_html(url: str, session: ClientSession, **kwargs) -> tuple: 
  5.     try: 
  6.         resp = await session.request(method="GET", url=url, **kwargs) 
  7.     except ClientConnectorError: 
  8.         return (url, 404) 
  9.     return (url, resp.status) 
  10.  
  11. async def make_requests(urls: set, **kwargs) -> None: 
  12.     async with ClientSession() as session: 
  13.         tasks = [] 
  14.         for url in urls: 
  15.             tasks.append( 
  16.                 fetch_html(url=url, session=session, **kwargs) 
  17.             ) 
  18.         results = await asyncio.gather(*tasks) 
  19.  
  20.     for result in results: 
  21.         print(f'{result[1]} - {str(result[0])}'
  22.  
  23. if __name__ == "__main__"
  24.     import sys 
  25.     assert sys.version_info >= (3, 7), "Script requires Python 3.7+." 
  26.     with open("urllist.txt"as infile: 
  27.         urls = set(map(str.strip, infile)) 
  28.     asyncio.run(make_requests(urls=urls)) 

grequests[1]

這是個第三方庫,目前有 3.8K 個星,就是 Requests + Gevent[2],讓異步 http 請求變得更加簡單。Gevent 的本質(zhì)還是協(xié)程。

使用前:

  1. pip install grequests 

使用起來那是相當?shù)暮唵危?/p>

  1. import grequests 
  2.  
  3. urls = [] 
  4. with open("urllist.txt"as reader: 
  5.     for url in reader: 
  6.         urls.append(url.strip()) 
  7.  
  8. rs = (grequests.get(u) for u in urls) 
  9.  
  10. for result in grequests.map(rs): 
  11.     print(result.status_code, result.url) 

注意 grequests.map(rs) 是并發(fā)執(zhí)行的。運行結(jié)果如下:

也可以加入異常處理:

  1. >>> def exception_handler(request, exception): 
  2. ...    print("Request failed"
  3.  
  4. >>> reqs = [ 
  5. ...    grequests.get('http://httpbin.org/delay/1', timeout=0.001), 
  6. ...    grequests.get('http://fakedomain/'), 
  7. ...    grequests.get('http://httpbin.org/status/500')] 
  8. >>> grequests.map(reqs, exception_handler=exception_handler) 
  9. Request failed 
  10. Request failed 
  11. [None, None, <Response [500]>] 

最后的話 

今天分享了并發(fā) http 請求的幾種實現(xiàn)方式,有人說異步(協(xié)程)性能比多線程好,其實要分場景看的,沒有一種方法適用所有的場景,筆者就曾做過一個實驗,也是請求 url,當并發(fā)數(shù)量超過 500 時,協(xié)程明顯變慢。

 

責任編輯:武曉燕 來源: Python七號
相關(guān)推薦

2017-09-15 09:43:59

Go語言web請求開發(fā)

2025-04-27 01:22:00

QPS高并發(fā)MySQL

2023-11-27 08:57:24

GoGET

2022-03-24 14:49:57

HTTP前端

2022-04-14 20:43:24

JavaScript原型鏈

2022-07-03 17:55:53

HTTP頁面瀏覽器

2010-09-08 15:35:35

2021-07-27 14:50:15

axiosHTTP前端

2024-07-04 13:42:12

2022-11-22 08:41:22

curlDELETELinux

2025-02-06 08:09:20

POSTGET數(shù)據(jù)

2013-03-22 17:34:07

BlackBerry1BB10黑莓

2022-06-21 15:00:01

Python語言循環(huán)方式

2024-12-19 10:00:00

Python發(fā)送消息編程

2023-09-14 08:16:51

2024-09-29 10:46:01

2011-08-03 14:33:54

IOS4.2 HTTP 請求

2021-03-06 09:54:22

PythonHTTP請求頭

2021-11-06 19:43:34

Python微信服務器

2018-02-24 16:15:03

PythonHTTP
點贊
收藏

51CTO技術(shù)棧公眾號