Python的进程和线程(二)——IO密集型任务
一、什么是IO密集型任務?
主要的核心任務是進行IO操作,比如寫文件,進行磁盤的讀寫等等。
上一篇博客,對計算密集型任務,多線程并沒有體現它的好處,反而話費的時間更長。對IO密集型任務多線程會有明顯的優勢
二、舉例:
任務:爬取韓寒的博客
1、獲取urls,
2、根據文章的url,爬取內容,保存文件
3、將urls分給不同的進程/線程
4、多進程/多線程爬取
step1:爬取urls
思路:用requests庫來爬取頁面,用beautifulSoup庫來獲取目標的urls值
import requests from bs4 import BeautifulSoupdef get_urls(url):'''獲取目標URL:param url: 列表頁面url:return: 目標url列表'''res=requests.get(url).textsoup = BeautifulSoup(res, features="html.parser")#通過css selector解析頁面,獲取元素artile_urls=soup.select(".atc_title > a")url_list=list(i.get("href") for i in artile_urls)return(url_list)step2:根據文章的url,爬取內容,保存文件
import time,os import requests from bs4 import BeautifulSoupdef get_content(urls,dirpath):'''獲取文章內容:param urls: 要獲取文章的url列表:param dirpath: 文章內容文件保存路徑:return: '''for url in urls:# print("要抓取的url是%s" % url)res = requests.get(url).content.decode("utf-8")soup = BeautifulSoup(res, features="html.parser")paragraphs = soup.select("#sina_keyword_ad_area2 > p")content=""for i in paragraphs:content+=i.get_text()if not os.path.exists(dirpath):os.makedirs(dirpath)open(dirpath + r'/' + url[-26:], 'w').write(content)step3:將urls分給不同的進程/線程?
思路:
假設我們啟動n個進程,一共要爬取的url列表是urls,列表的長度為url_len
我們先把列表整除n得到長度為L(不一定能夠整除,所以最后一個進程為總數-前面n-1個進程的),則第1個進程要爬取的url列表是urls[0:L],第2個進程要爬取的url列表是url[L: 2L],依次類推。。。。,最后一個進程要爬取的url列表是url[i*n:url_len]
for n in [8, 4, 2, 1]:# 將urls分割到url_listurl_list = []url_split_len = url_len // nfor i in range(n):if i == n - 1:url_list.append(urls[i * url_split_len:url_len])else:url_list.append(urls[i * url_split_len:(i + 1) * url_split_len])?
參照上一篇博客,多進程和多線程函數。
我們的目標函數是,get_content,這個函數需要2個參數,一個是url列表,一個是保存文件的路徑
import timedef thread_process_job(n, Thread_or_Process, url_list, job):"""n: 多線程或多進程數Thread_Process: Thread/Process類job: countdown任務"""local_time = time.time()# 實例化多線程或多進程threads_or_processes = [Thread_or_Process(target=job, args=(url_list[j],str(n)+Thread_or_Process.__name__)) for j in range(n)]for t in threads_or_processes:t.start() # 開始線程或進程,必須調用for t in threads_or_processes:t.join() # 等待直到該線程或進程結束print(n, Thread_or_Process.__name__, " run job need ", time.time() - local_time)?step4:多進程或者多線程爬取
我們爬取前6頁的數據,代碼如下
if __name__=="__main__":t = time.time()urls = []for i in range(7):url='http://blog.sina.com.cn/s/articlelist_1191258123_0_' + str(i + 1) + '.html'page_urls=get_urls(url)urls.extend(page_urls)url_len = len(urls)print("total urls number is ", url_len)for n in [8, 4, 2, 1]:# 將urls分割到url_listurl_list = []url_split_len = url_len // nfor i in range(n):if i == n - 1:url_list.append(urls[i * url_split_len:url_len])else:url_list.append(urls[i * url_split_len:(i + 1) * url_split_len])# 分割任務后創建線程 thread_process_job(n, Thread, url_list, get_content)thread_process_job(n, Process, url_list, get_content)print("All done in ", time.time() - t)代碼可能存在的問題:
代碼在運行中,可能會存在的問題是,調用get_content函數時,可能一個進程正在創建文件夾,一個進程正好在判斷文件不存在要創建,在創建的時候會報錯文件已存在。
?
轉載于:https://www.cnblogs.com/yimiaoyikan/p/10485207.html
總結
以上是生活随笔為你收集整理的Python的进程和线程(二)——IO密集型任务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浏览器的缓存机制
- 下一篇: css3动画、2D与3D效果