一文帶你掌握Python中多線程和線程池的使用方法
Python是一種高級(jí)編程語(yǔ)言,它在眾多編程語(yǔ)言中,擁有極高的人氣和使用率。Python中的多線程和線程池是其強(qiáng)大的功能之一,可以讓我們更加高效地利用CPU資源,提高程序的運(yùn)行速度。本篇博客將介紹Python中多線程和線程池的使用方法,并提供一些實(shí)用的案例供讀者參考。
一、多線程
多線程是指在同一進(jìn)程中,有多個(gè)線程同時(shí)執(zhí)行不同的任務(wù)。Python中的多線程是通過threading模塊來實(shí)現(xiàn)的。下面是一個(gè)簡(jiǎn)單的多線程示例:
import threading def task(num): print('Task %d is running.' % num) if __name__ == '__main__': for i in range(5): t = threading.Thread(target=task, args=(i,)) t.start()
上述代碼中,我們定義了一個(gè)task函數(shù),它接受一個(gè)參數(shù)num,用于標(biāo)識(shí)任務(wù)。在主程序中,我們創(chuàng)建了5個(gè)線程,每個(gè)線程都執(zhí)行task函數(shù),并傳入不同的參數(shù)。通過start()方法啟動(dòng)線程。運(yùn)行上述代碼,可以看到輸出結(jié)果類似于下面這樣:
Task 0 is running.
Task 1 is running.
Task 2 is running.
Task 3 is running.
Task 4 is running.
由于多線程是并發(fā)執(zhí)行的,因此輸出結(jié)果的順序可能會(huì)有所不同。
二、線程池
線程池是一種管理多線程的機(jī)制,它可以預(yù)先創(chuàng)建一定數(shù)量的線程,并將任務(wù)分配給這些線程執(zhí)行。Python中的線程池是通過ThreadPoolExecutor類來實(shí)現(xiàn)的。下面是一個(gè)簡(jiǎn)單的線程池示例:
import concurrent.futures def task(num): print('Task %d is running.' % num) if __name__ == '__main__': with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: for i in range(5): executor.submit(task, i)
上述代碼中,我們使用了with語(yǔ)句創(chuàng)建了一個(gè)ThreadPoolExecutor對(duì)象,其中max_workers參數(shù)指定了線程池中最大的線程數(shù)量。在主程序中,我們創(chuàng)建了5個(gè)任務(wù),每個(gè)任務(wù)都通過executor.submit()方法提交給線程池執(zhí)行。運(yùn)行上述代碼,可以看到輸出結(jié)果類似于下面這樣:
Task 0 is running.
Task 1 is running.
Task 2 is running.
Task 3 is running.
Task 4 is running.
由于線程池中最大的線程數(shù)量為3,因此只有3個(gè)任務(wù)可以同時(shí)執(zhí)行,其他任務(wù)需要等待線程池中的線程空閑后再執(zhí)行。
三、使用案例
下面是一個(gè)實(shí)際的案例,展示了如何使用多線程和線程池來加速數(shù)據(jù)處理過程。假設(shè)我們有一個(gè)包含1000個(gè)元素的列表,需要對(duì)每個(gè)元素進(jìn)行某種運(yùn)算,并將結(jié)果保存到另一個(gè)列表中。我們可以使用單線程的方式來實(shí)現(xiàn):
def process(data): result = [] for item in data: result.append(item * 2) return result if __name__ == '__main__': data = list(range(1000)) result = process(data) print(result)
上述代碼中,我們定義了一個(gè)process函數(shù),它接受一個(gè)列表作為參數(shù),對(duì)列表中的每個(gè)元素進(jìn)行運(yùn)算,并將結(jié)果保存到另一個(gè)列表中。在主程序中,我們創(chuàng)建了一個(gè)包含1000個(gè)元素的列表,并將其傳遞給process函數(shù)。運(yùn)行上述代碼,可以看到輸出結(jié)果類似于下面這樣:
[0, 2, 4, 6, 8, ..., 1996, 1998]
Python中的多線程和線程池可以提高爬蟲的效率,本文將介紹一個(gè)爬取豆瓣電影Top250的案例,并通過多線程和線程池優(yōu)化爬取過程。
1.單線程爬取
首先,我們先來看一下單線程爬取的代碼:
# -*- coding: utf-8 -*- import requests from bs4 import BeautifulSoup def get_html(url): try: response = requests.get(url) if response.status_code == 200: return response.text else: return None except Exception as e: print(e) def parse_html(html): soup = BeautifulSoup(html, 'lxml') movie_list = soup.find(class_='grid_view').find_all('li') for movie in movie_list: title = movie.find(class_='title').string rating = movie.find(class_='rating_num').string print(title, rating) def main(): url = 'https://movie.douban.com/top250' html = get_html(url) parse_html(html) if __name__ == '__main__': main()
這是一個(gè)簡(jiǎn)單的爬取豆瓣電影Top250的代碼,首先通過requests庫(kù)獲取網(wǎng)頁(yè)的HTML代碼,然后使用BeautifulSoup庫(kù)解析HTML代碼,獲取電影名稱和評(píng)分。
但是,這種單線程爬取的方式效率較低,因?yàn)樵讷@取HTML代碼的時(shí)候需要等待響應(yīng),而在等待響應(yīng)的過程中CPU會(huì)空閑,無法充分利用計(jì)算機(jī)的性能。
2.多線程爬取
接下來,我們通過多線程的方式來優(yōu)化爬取過程。首先,我們需要導(dǎo)入Python中的threading庫(kù):
import threading
然后,我們將獲取HTML代碼的代碼放在一個(gè)函數(shù)中,并將其作為一個(gè)線程來運(yùn)行:
def get_html(url): try: response = requests.get(url) if response.status_code == 200: return response.text else: return None except Exception as e: print(e) class GetHtmlThread(threading.Thread): def __init__(self, url): threading.Thread.__init__(self) self.url = url def run(self): html = get_html(self.url) parse_html(html)
在上面的代碼中,我們首先定義了一個(gè)GetHtmlThread類,繼承自threading.Thread類,然后在類的構(gòu)造函數(shù)中傳入需要爬取的URL。在run方法中,我們調(diào)用get_html函數(shù)獲取HTML代碼,并將其傳入parse_html函數(shù)中進(jìn)行解析。
接下來,我們通過循環(huán)創(chuàng)建多個(gè)線程來進(jìn)行爬?。?/p>
def main(): urls = ['https://movie.douban.com/top250?start={}'.format(i) for i in range(0, 250, 25)] threads = [] for url in urls: thread = GetHtmlThread(url) thread.start() threads.append(thread) for thread in threads: thread.join()
在上面的代碼中,我們首先定義了一個(gè)urls列表,包含了所有需要爬取的URL。然后通過循環(huán)創(chuàng)建多個(gè)GetHtmlThread線程,并將其加入到threads列表中。最后,通過循環(huán)調(diào)用join方法等待所有線程執(zhí)行完畢。
通過多線程的方式,我們可以充分利用計(jì)算機(jī)的性能,提高爬取效率。
3.線程池爬取
在多線程的方式中,我們需要手動(dòng)創(chuàng)建和管理線程,這樣會(huì)增加代碼的復(fù)雜度。因此,我們可以使用Python中的線程池來進(jìn)行優(yōu)化。
首先,我們需要導(dǎo)入Python中的concurrent.futures庫(kù):
import concurrent.futures
然后,我們將獲取HTML代碼的代碼放在一個(gè)函數(shù)中,并將其作為一個(gè)任務(wù)來提交給線程池:
def get_html(url): try: response = requests.get(url) if response.status_code == 200: return response.text else: return None except Exception as e: print(e) def parse_html(html): soup = BeautifulSoup(html, 'lxml') movie_list = soup.find(class_='grid_view').find_all('li') for movie in movie_list: title = movie.find(class_='title').string rating = movie.find(class_='rating_num').string print(title, rating) def main(): urls = ['https://movie.douban.com/top250?start={}'.format(i) for i in range(0, 250, 25)] with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: futures = [executor.submit(get_html, url) for url in urls] for future in concurrent.futures.as_completed(futures): html = future.result() parse_html(html)
在上面的代碼中,我們首先定義了一個(gè)urls列表,包含了所有需要爬取的URL。然后通過with語(yǔ)句創(chuàng)建一個(gè)線程池,并設(shè)置最大線程數(shù)為5。接下來,我們通過循環(huán)將每個(gè)URL提交給線程池,并將返回的Future對(duì)象加入到futures列表中。最后,通過concurrent.futures.as_completed函數(shù)來等待所有任務(wù)執(zhí)行完畢,并獲取返回值進(jìn)行解析。
通過線程池的方式,我們可以更加簡(jiǎn)潔地實(shí)現(xiàn)多線程爬取,并且可以更加靈活地控制線程的數(shù)量,避免線程過多導(dǎo)致系統(tǒng)負(fù)載過高的問題。
以上就是一文帶你掌握Python中多線程和線程池的使用方法的詳細(xì)內(nèi)容,更多關(guān)于Python多線程 線程池的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python tornado隊(duì)列示例-一個(gè)并發(fā)web爬蟲代碼分享
這篇文章主要介紹了Python tornado隊(duì)列示例-一個(gè)并發(fā)web爬蟲代碼分享,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01Python提取轉(zhuǎn)移文件夾內(nèi)所有.jpg文件并查看每一幀的方法
今天小編就為大家分享一篇Python提取轉(zhuǎn)移文件夾內(nèi)所有.jpg文件并查看每一幀的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-06-06pyqt5 comboBox獲得下標(biāo)、文本和事件選中函數(shù)的方法
今天小編就為大家分享一篇pyqt5 comboBox獲得下標(biāo)、文本和事件選中函數(shù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-06-06使用Python OpenCV為CNN增加圖像樣本的實(shí)現(xiàn)
這篇文章主要介紹了使用Python OpenCV為CNN增加圖像樣本的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-06-06Django之編輯時(shí)根據(jù)條件跳轉(zhuǎn)回原頁(yè)面的方法
今天小編就為大家分享一篇Django之編輯時(shí)根據(jù)條件跳轉(zhuǎn)回原頁(yè)面的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-08-08