您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Python中多線程和線程池如何使用”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Python中多線程和線程池如何使用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
多線程是指在同一進程中,有多個線程同時執行不同的任務。Python中的多線程是通過threading模塊來實現的。下面是一個簡單的多線程示例:
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()
上述代碼中,我們定義了一個task函數,它接受一個參數num,用于標識任務。在主程序中,我們創建了5個線程,每個線程都執行task函數,并傳入不同的參數。通過start()方法啟動線程。運行上述代碼,可以看到輸出結果類似于下面這樣:
Task 0 is running.
Task 1 is running.
Task 2 is running.
Task 3 is running.
Task 4 is running.
由于多線程是并發執行的,因此輸出結果的順序可能會有所不同。
線程池是一種管理多線程的機制,它可以預先創建一定數量的線程,并將任務分配給這些線程執行。Python中的線程池是通過ThreadPoolExecutor類來實現的。下面是一個簡單的線程池示例:
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語句創建了一個ThreadPoolExecutor對象,其中max_workers參數指定了線程池中最大的線程數量。在主程序中,我們創建了5個任務,每個任務都通過executor.submit()方法提交給線程池執行。運行上述代碼,可以看到輸出結果類似于下面這樣:
Task 0 is running.
Task 1 is running.
Task 2 is running.
Task 3 is running.
Task 4 is running.
由于線程池中最大的線程數量為3,因此只有3個任務可以同時執行,其他任務需要等待線程池中的線程空閑后再執行。
下面是一個實際的案例,展示了如何使用多線程和線程池來加速數據處理過程。假設我們有一個包含1000個元素的列表,需要對每個元素進行某種運算,并將結果保存到另一個列表中。我們可以使用單線程的方式來實現:
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)
上述代碼中,我們定義了一個process函數,它接受一個列表作為參數,對列表中的每個元素進行運算,并將結果保存到另一個列表中。在主程序中,我們創建了一個包含1000個元素的列表,并將其傳遞給process函數。運行上述代碼,可以看到輸出結果類似于下面這樣:
[0, 2, 4, 6, 8, ..., 1996, 1998]
Python中的多線程和線程池可以提高爬蟲的效率,本文將介紹一個爬取豆瓣電影Top250的案例,并通過多線程和線程池優化爬取過程。
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()
這是一個簡單的爬取豆瓣電影Top250的代碼,首先通過requests庫獲取網頁的HTML代碼,然后使用BeautifulSoup庫解析HTML代碼,獲取電影名稱和評分。
但是,這種單線程爬取的方式效率較低,因為在獲取HTML代碼的時候需要等待響應,而在等待響應的過程中CPU會空閑,無法充分利用計算機的性能。
2.多線程爬取
接下來,我們通過多線程的方式來優化爬取過程。首先,我們需要導入Python中的threading庫:
import threading
然后,我們將獲取HTML代碼的代碼放在一個函數中,并將其作為一個線程來運行:
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)
在上面的代碼中,我們首先定義了一個GetHtmlThread類,繼承自threading.Thread類,然后在類的構造函數中傳入需要爬取的URL。在run方法中,我們調用get_html函數獲取HTML代碼,并將其傳入parse_html函數中進行解析。
接下來,我們通過循環創建多個線程來進行爬取:
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()
在上面的代碼中,我們首先定義了一個urls列表,包含了所有需要爬取的URL。然后通過循環創建多個GetHtmlThread線程,并將其加入到threads列表中。最后,通過循環調用join方法等待所有線程執行完畢。
通過多線程的方式,我們可以充分利用計算機的性能,提高爬取效率。
3.線程池爬取
在多線程的方式中,我們需要手動創建和管理線程,這樣會增加代碼的復雜度。因此,我們可以使用Python中的線程池來進行優化。
首先,我們需要導入Python中的concurrent.futures庫:
import concurrent.futures
然后,我們將獲取HTML代碼的代碼放在一個函數中,并將其作為一個任務來提交給線程池:
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)
在上面的代碼中,我們首先定義了一個urls列表,包含了所有需要爬取的URL。然后通過with語句創建一個線程池,并設置最大線程數為5。接下來,我們通過循環將每個URL提交給線程池,并將返回的Future對象加入到futures列表中。最后,通過concurrent.futures.as_completed函數來等待所有任務執行完畢,并獲取返回值進行解析。
通過線程池的方式,我們可以更加簡潔地實現多線程爬取,并且可以更加靈活地控制線程的數量,避免線程過多導致系統負載過高的問題。
讀到這里,這篇“Python中多線程和線程池如何使用”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。