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

Python實(shí)用技巧大任務(wù)切分

開發(fā) 后端
今天來說說,Python 中的任務(wù)切分。以爬蟲為例,從一個(gè)存 url 的 txt 文件中,讀取其內(nèi)容,我們會(huì)獲取一個(gè) url 列表。我們把這一個(gè) url 列表稱為大任務(wù)。

 今天來說說,Python 中的任務(wù)切分。以爬蟲為例,從一個(gè)存 url 的 txt 文件中,讀取其內(nèi)容,我們會(huì)獲取一個(gè) url 列表。我們把這一個(gè) url 列表稱為大任務(wù)。

[[283503]]

列表切分在

不考慮內(nèi)存占用的情況下,我們對(duì)上面的大任務(wù)進(jìn)行一個(gè)切分。比如我們將大任務(wù)切分成的小任務(wù)是每秒最多只訪問5個(gè)URL。

 

  1. import os 
  2. import time 
  3.  
  4. CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) 
  5.  
  6. def read_file(): 
  7.     file_path = os.path.join(CURRENT_DIR, "url_list.txt"
  8.     with open(file_path, "r", encoding="utf-8"as fs: 
  9.         result = [i.strip() for i in fs.readlines()] 
  10.     return result 
  11.  
  12. def fetch(url): 
  13.     print(url) 
  14.  
  15. def run(): 
  16.     max_count = 5 
  17.     url_list = read_file() 
  18.     for index in range(0, len(url_list), max_count): 
  19.         start = time.time() 
  20.         fetch(url_list[index:index + max_count]) 
  21.         end = time.time() - start 
  22.         if end < 1: 
  23.             time.sleep(1 - end
  24.  
  25.  
  26. if __name__ == '__main__'
  27.     run() 

關(guān)鍵代碼都在for循環(huán)里,首先我們通過聲明range的第三個(gè)參數(shù),該參數(shù)指定迭代的步長(zhǎng)為5,這樣每次index增加都是以5為基數(shù),即0,5,10。。。

然后我們對(duì)url_list做切片,每次取其五個(gè)元素,這五個(gè)元素會(huì)隨著index的增加不斷的在改變,如果最后不夠五個(gè)了,按照切片的特性這個(gè)時(shí)候就會(huì)有多少取多少了,不會(huì)造成索引超下標(biāo)的問題。

隨著url列表的增加,我們會(huì)發(fā)現(xiàn)內(nèi)存的占用也在提高了。這個(gè)時(shí)候我們就需要對(duì)代碼進(jìn)行修改了,我們知道生成器是比較節(jié)省內(nèi)存的空間的,修改之后代碼變成,下面的這樣。

生成器切分

 

  1. # -*- coding: utf-8 -*- 
  2. # @時(shí)間 : 2019-11-23 23:47 
  3. # @作者 : 陳祥安 
  4. # @文件名 : g.py 
  5. # @公眾號(hào): Python學(xué)習(xí)開發(fā) 
  6. import os 
  7. import time 
  8. from itertools import islice 
  9.  
  10. CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) 
  11.  
  12.  
  13. def read_file(): 
  14.     file_path = os.path.join(CURRENT_DIR, "url_list.txt"
  15.     with open(file_path, "r", encoding="utf-8"as fs: 
  16.         for i in fs: 
  17.             yield i.strip() 
  18.  
  19.  
  20. def fetch(url): 
  21.     print(url) 
  22.  
  23.  
  24. def run(): 
  25.     max_count = 5 
  26.     url_gen = read_file() 
  27.     while True
  28.         url_list = list(islice(url_gen, 0, max_count)) 
  29.         if not url_list: 
  30.             break 
  31.         start = time.time() 
  32.         fetch(url_list) 
  33.         end = time.time() - start 
  34.         if end < 1: 
  35.             time.sleep(1 - end
  36.  
  37.  
  38. if __name__ == '__main__'
  39.     run() 

首先,我們修改了文件讀取的方式,把原來讀列表的形式,改為了生成器的形式。這樣我們?cè)谡{(diào)用該文件讀取方法的時(shí)候大大節(jié)省了內(nèi)存。

然后就是對(duì)上面for循環(huán)進(jìn)行改造,因?yàn)樯善鞯奶匦裕@里不適合使用for進(jìn)行迭代,因?yàn)槊恳淮蔚牡紩?huì)消耗生成器的元素,通過使用itertools的islice對(duì)url_gen進(jìn)行切分,islice是生成器的切片,這里我們每次切分出含有5個(gè)元素的生成器,因?yàn)樯善鳑]有__len__方法所以,我們將其轉(zhuǎn)為列表,然后判斷列表是否為空,就可以知道迭代是否該結(jié)束了。

修改之后的代碼,不管是性能還是節(jié)省內(nèi)存上都大大的提高。讀取千萬級(jí)的文件不是問題。

除此之外,在使用異步爬蟲的時(shí)候,也許會(huì)用到異步生成器切片。下面就和大家討論,異步生成器切分的問題

異步生成器切分

首先先來看一個(gè)簡(jiǎn)單的異步生成器。

我們知道調(diào)用下面的代碼會(huì)得到一個(gè)生成器

 

  1. def foo(): 
  2.     for i in range(20): 
  3.         yield i 

如果在def前面加一個(gè)async,那么在調(diào)用的時(shí)候它就是個(gè)異步生成器了。

完整示例代碼如下

 

  1. import asyncio 
  2. async def foo(): 
  3.     for i in range(20): 
  4.         yield i 
  5.  
  6.  
  7. async def run(): 
  8.     async_gen = foo() 
  9.     async for i in async_gen: 
  10.         print(i) 
  11.  
  12.  
  13. if __name__ == '__main__'
  14.     asyncio.run(run()) 

關(guān)于async for的切分有點(diǎn)復(fù)雜,這里推薦使用aiostream模塊,使用之后代碼改為下面這樣

 

  1. import asyncio 
  2. from aiostream import stream 
  3.  
  4. async def foo(): 
  5.     for i in range(22): 
  6.         yield i 
  7.  
  8.  
  9. async def run(): 
  10.     index = 0 
  11.     limit = 5 
  12.  
  13.     while True
  14.         xs = stream.iterate(foo()) 
  15.         ys = xs[index:index + limit] 
  16.         t = await stream.list(ys) 
  17.         if not t: 
  18.             break 
  19.         print(t) 
  20.         index += limit 
  21.  
  22.  
  23. if __name__ == '__main__'
  24.     asyncio.run(run()) 

 

責(zé)任編輯:華軒 來源: Python學(xué)習(xí)開發(fā)
相關(guān)推薦

2009-09-04 10:27:28

Linux實(shí)用技巧linux操作系統(tǒng)linux

2022-03-23 09:18:10

Git技巧Linux

2009-12-21 15:50:39

2009-01-03 09:34:30

ASP.NET.NET性能優(yōu)化

2011-04-08 15:40:01

Oracle認(rèn)證

2022-10-11 08:00:47

多線程開發(fā)技巧

2022-11-03 10:28:59

PandasSAC機(jī)制

2024-05-17 08:52:43

SQL實(shí)用技巧行列轉(zhuǎn)換

2024-05-22 09:29:43

2010-09-14 10:41:24

DIV+CSS排版

2009-12-09 11:21:30

Linux實(shí)用技巧

2019-12-22 23:10:19

LinuxSSH加密

2010-10-08 15:44:17

vim

2009-12-23 17:32:35

Linux構(gòu)建軟路由

2019-10-10 16:31:51

PyCharmPythonWindows

2021-11-15 10:02:16

Python命令技巧

2023-04-26 00:34:36

Python技巧程序員

2024-09-11 16:30:55

Python函數(shù)編程

2011-06-21 10:02:29

Python

2018-05-10 17:39:13

Python 機(jī)器學(xué)習(xí)編程語(yǔ)言
點(diǎn)贊
收藏

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