最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python多線程中線程數(shù)量如何控制

 更新時(shí)間:2023年01月06日 09:14:12   作者:Python熱愛者  
本文主要介紹了Python多線程中線程數(shù)量如何控制,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

前段時(shí)間學(xué)習(xí)了python的多線程爬蟲,當(dāng)時(shí)爬取一個(gè)圖片網(wǎng)站,開啟多線程后,并沒有限制線程的數(shù)量,也就是說,如果下載1000張圖片,會(huì)一次性開啟1000個(gè)子線程同時(shí)進(jìn)行下載

現(xiàn)在希望控制線程數(shù)量:例如每次只下載5張,當(dāng)下載完成后再下載另外5張,直至全部完成

查了一些資料,發(fā)現(xiàn)在python中,threading 模塊有提供 Semaphore類 和 BoundedSemaphore類來限制線程數(shù)

官網(wǎng)給出例子如下:

信號(hào)量通常用于保護(hù)容量有限的資源,例如數(shù)據(jù)庫服務(wù)器。在資源大小固定的任何情況下,都應(yīng)使用有界信號(hào)量。在產(chǎn)生任何工作線程之前,您的主線程將初始化信號(hào)量:

maxconnections = 5
# ...
pool_sema = BoundedSemaphore(value=maxconnections)

產(chǎn)生后,工作線程在需要連接到服務(wù)器時(shí)會(huì)調(diào)用信號(hào)量的獲取和釋放方法:

改造之前的多線程爬蟲

首先貼出原來的代碼

# -*- coding:utf-8 -*-
import requests
from requests.exceptions import RequestException
import os, time
import re
from lxml import etree
import threading

lock = threading.Lock()
def get_html(url):
? ? """
? ? 定義一個(gè)方法,用于獲取一個(gè)url頁面的響應(yīng)內(nèi)容
? ? :param url: 要訪問的url
? ? :return: 響應(yīng)內(nèi)容
? ? """
? ? response = requests.get(url, timeout=10)
? ? # print(response.status_code)
? ? try:
? ? ? ? if response.status_code == 200:

? ? ? ? ? ? # print(response.text)
? ? ? ? ? ? return response.text
? ? ? ? else:
? ? ? ? ? ? ?return None
? ? except RequestException:
? ? ? ? print("請(qǐng)求失敗")
? ? ? ? # return None


def parse_html(html_text):
? ? """
? ? 定義一個(gè)方法,用于解析頁面內(nèi)容,提取圖片url
? ? :param html_text:
? ? :return:一個(gè)頁面的圖片url集合
? ? """
? ? html = etree.HTML(html_text)

? ? if len(html) > 0:
? ? ? ? img_src = html.xpath("http://img[@class='photothumb lazy']/@data-original") ?# 元素提取方法
? ? ? ? # print(img_src)
? ? ? ? return img_src

? ? else:
? ? ? ? print("解析頁面元素失敗")

def get_image_pages(url):
? ? """
? ? 獲取所查詢圖片結(jié)果的所有頁碼
? ? :param url: 查詢圖片url
? ? :return: 總頁碼數(shù)
? ? """

? ? html_text = get_html(url) ?# 獲取搜索url響應(yīng)內(nèi)容
? ? # print(html_text)
? ? if html_text is not None:
? ? ? ? html = etree.HTML(html_text) ?# 生成XPath解析對(duì)象
? ? ? ? last_page = html.xpath("http://div[@class='pages']//a[last()]/@href") ?# 提取最后一頁所在href鏈接
? ? ? ? print(last_page)
? ? ? ? if last_page:
? ? ? ? ? ? max_page = re.compile(r'(\d+)', re.S).search(last_page[0]).group() ?# 使用正則表達(dá)式提取鏈接中的頁碼數(shù)字
? ? ? ? ? ? print(max_page)
? ? ? ? ? ? print(type(max_page))
? ? ? ? ? ? return int(max_page) ?# 將字符串頁碼轉(zhuǎn)為整數(shù)并返回
? ? ? ? else:
? ? ? ? ? ? print("暫無數(shù)據(jù)")
? ? ? ? ? ? return None
? ? else:
? ? ? ? print("查詢結(jié)果失敗")


def get_all_image_url(page_number):
? ? """
? ? 獲取所有圖片的下載url
? ? :param page_number: 爬取頁碼
? ? :return: 所有圖片url的集合
? ? """

? ? base_url = 'https://imgbin.com/free-png/naruto/'
? ? image_urls = []

? ? x = 1 ?# 定義一個(gè)標(biāo)識(shí),用于給每個(gè)圖片url編號(hào),從1遞增
? ? for i in range(1, page_number):
? ? ? ? url = base_url + str(i) ?# 根據(jù)頁碼遍歷請(qǐng)求url
? ? ? ? try:
? ? ? ? ? ? html = get_html(url) ?# 解析每個(gè)頁面的內(nèi)容
? ? ? ? ? ? if html:
? ? ? ? ? ? ? ? data = parse_html(html) ?# 提取頁面中的圖片url
? ? ? ? ? ? ? ? # print(data)
? ? ? ? ? ? ? ? # time.sleep(3)
? ? ? ? ? ? ? ? if data:
? ? ? ? ? ? ? ? ? ? for j in data:
? ? ? ? ? ? ? ? ? ? ? ? image_urls.append({
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'name': x,
? ? ? ? ? ? ? ? ? ? ? ? ? ? 'value': j
? ? ? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? ? ? ? ? x += 1 ?# 每提取一個(gè)圖片url,標(biāo)識(shí)x增加1
? ? ? ? except RequestException as f:
? ? ? ? ? ? print("遇到錯(cuò)誤:", f)
? ? ? ? ? ? continue
? ? # print(image_urls)
? ? return image_urls

def get_image_content(url):
? ? """請(qǐng)求圖片url,返回二進(jìn)制內(nèi)容"""
? ? # print("正在下載", url)
? ? try:
? ? ? ? r = requests.get(url, timeout=15)
? ? ? ? if r.status_code == 200:
? ? ? ? ? ? return r.content
? ? ? ? return None
? ? except RequestException:
? ? ? ? return None

def main(url, image_name):
? ? """
? ? 主函數(shù):實(shí)現(xiàn)下載圖片功能
? ? :param url: 圖片url
? ? :param image_name: 圖片名稱
? ? :return:
? ? """
? ? semaphore.acquire() ?# 加鎖,限制線程數(shù)
? ? print('當(dāng)前子線程: {}'.format(threading.current_thread().name))
? ? save_path = os.path.dirname(os.path.abspath('.')) + '/pics/'
? ? try:
? ? ? ? file_path = '{0}/{1}.jpg'.format(save_path, image_name)
? ? ? ? if not os.path.exists(file_path): ?# 判斷是否存在文件,不存在則爬取
? ? ? ? ? ? with open(file_path, 'wb') as f:
? ? ? ? ? ? ? ? f.write(get_image_content(url))
? ? ? ? ? ? ? ? f.close()

? ? ? ? ? ? ? ? print('第{}個(gè)文件保存成功'.format(image_name))

? ? ? ? else:
? ? ? ? ? ? print("第{}個(gè)文件已存在".format(image_name))

? ? ? ? semaphore.release() ?# 解鎖imgbin-多線程-重寫run方法.py

? ? except FileNotFoundError as f:
? ? ? ? print("第{}個(gè)文件下載時(shí)遇到錯(cuò)誤,url為:{}:".format(image_name, url))
? ? ? ? print("報(bào)錯(cuò):", f)
? ? ? ? raise

? ? except TypeError as e:
? ? ? ? print("第{}個(gè)文件下載時(shí)遇到錯(cuò)誤,url為:{}:".format(image_name, url))
? ? ? ? print("報(bào)錯(cuò):", e)

class MyThread(threading.Thread):
? ? """繼承Thread類重寫run方法創(chuàng)建新進(jìn)程"""
? ? def __init__(self, func, args):
? ? ? ? """

? ? ? ? :param func: run方法中要調(diào)用的函數(shù)名
? ? ? ? :param args: func函數(shù)所需的參數(shù)
? ? ? ? """
? ? ? ? threading.Thread.__init__(self)
? ? ? ? self.func = func
? ? ? ? self.args = args

? ? def run(self):
? ? ? ? print('當(dāng)前子線程: {}'.format(threading.current_thread().name))
? ? ? ? self.func(self.args[0], self.args[1])
? ? ? ? # 調(diào)用func函數(shù)
? ? ? ? # 因?yàn)檫@里的func函數(shù)其實(shí)是上述的main()函數(shù),它需要2個(gè)參數(shù);args傳入的是個(gè)參數(shù)元組,拆解開來傳入


if __name__ == '__main__':
? ? start = time.time()
? ? print('這是主線程:{}'.format(threading.current_thread().name))

? ? urls = get_all_image_url(5) ?# 獲取所有圖片url列表
? ? thread_list = [] ?# 定義一個(gè)列表,向里面追加線程
? ? semaphore = threading.BoundedSemaphore(5) # 或使用Semaphore方法
? ? for t in urls:
? ? ? ? # print(i)

? ? ? ? m = MyThread(main, (t["value"], t["name"])) ?# 調(diào)用MyThread類,得到一個(gè)實(shí)例

? ? ? ? thread_list.append(m)

? ? for m in thread_list:

? ? ? ? m.start() ?# 調(diào)用start()方法,開始執(zhí)行

? ? for m in thread_list:
? ? ? ? m.join() ?# 子線程調(diào)用join()方法,使主線程等待子線程運(yùn)行完畢之后才退出


? ? end = time.time()
? ? print(end-start)
? ? # get_image_pages("https://imgbin.com/free-png/Naruto")

將代碼進(jìn)行改造

1、下面的第8、9行表示調(diào)用 threading 的 BoundedSemaphore類,初始化信號(hào)量為5,把結(jié)果賦給變量 pool_sema

if __name__ == '__main__':
? ? start = time.time()
? ? print('這是主線程:{}'.format(threading.current_thread().name))

? ? urls = get_all_image_url(5) ?# 獲取所有圖片url列表
? ? thread_list = [] ?# 定義一個(gè)列表,向里面追加線程
?? ?# 更多Python相關(guān)視頻、資料加群778463939免費(fèi)獲取
? ? max_connections = 5 ?# 定義最大線程數(shù)
? ? pool_sema = threading.BoundedSemaphore(max_connections) # 或使用Semaphore方法
? ? for t in urls:
? ? ? ? # print(i)

? ? ? ? m = MyThread(main, (t["value"], t["name"])) ?# 調(diào)用MyThread類,得到一個(gè)實(shí)例

? ? ? ? thread_list.append(m)

? ? for m in thread_list:

? ? ? ? m.start() ?# 調(diào)用start()方法,開始執(zhí)行

? ? for m in thread_list:
? ? ? ? m.join() ?# 子線程調(diào)用join()方法,使主線程等待子線程運(yùn)行完畢之后才退出


? ? end = time.time()
? ? print(end-start)

2、修改main()函數(shù)

(1)方法一:通過with語句實(shí)現(xiàn),第9行添加 with pool_sema

使用 with 語句來獲得一個(gè)鎖、條件變量或信號(hào)量,相當(dāng)于調(diào)用 acquire();離開 with 塊后,會(huì)自動(dòng)調(diào)用 release()

def main(url, image_name):
? ? """
? ? 主函數(shù):實(shí)現(xiàn)下載圖片功能
? ? :param url: 圖片url
? ? :param image_name: 圖片名稱
? ? :return:
? ? """

? ? with pool_sema:
? ? ? ? print('當(dāng)前子線程: {}'.format(threading.current_thread().name))
? ? ? ? save_path = os.path.dirname(os.path.abspath('.')) + '/pics/'
? ? ? ? try:
? ? ? ? ? ? file_path = '{0}/{1}.jpg'.format(save_path, image_name)
? ? ? ? ? ? if not os.path.exists(file_path): ?# 判斷是否存在文件,不存在則爬取
? ? ? ? ? ? ? ? with open(file_path, 'wb') as f:
? ? ? ? ? ? ? ? ? ? f.write(get_image_content(url))
? ? ? ? ? ? ? ? ? ? f.close()

? ? ? ? ? ? ? ? ? ? print('第{}個(gè)文件保存成功'.format(image_name))

? ? ? ? ? ? else:
? ? ? ? ? ? ? ? print("第{}個(gè)文件已存在".format(image_name))

? ? ? ? except FileNotFoundError as f:
? ? ? ? ? ? print("第{}個(gè)文件下載時(shí)遇到錯(cuò)誤,url為:{}:".format(image_name, url))
? ? ? ? ? ? print("報(bào)錯(cuò):", f)
? ? ? ? ? ? raise

? ? ? ? except TypeError as e:
? ? ? ? ? ? print("第{}個(gè)文件下載時(shí)遇到錯(cuò)誤,url為:{}:".format(image_name, url))
? ? ? ? ? ? print("報(bào)錯(cuò):", e)

(2)方法二:直接使用 acquire()和 release()

下面的第8行調(diào)用 acquire(),第24行調(diào)用release()

def main(url, image_name):
? ? """
? ? 主函數(shù):實(shí)現(xiàn)下載圖片功能
? ? :param url: 圖片url
? ? :param image_name: 圖片名稱
? ? :return:
? ? """
? ? pool_sema.acquire() ?# 加鎖,限制線程數(shù)
? ? # with pool_sema:
? ? print('當(dāng)前子線程: {}'.format(threading.current_thread().name))
? ? save_path = os.path.dirname(os.path.abspath('.')) + '/pics/'
? ? try:
? ? ? ? file_path = '{0}/{1}.jpg'.format(save_path, image_name)
? ? ? ? if not os.path.exists(file_path): ?# 判斷是否存在文件,不存在則爬取
? ? ? ? ? ? with open(file_path, 'wb') as f:
? ? ? ? ? ? ? ? f.write(get_image_content(url))
? ? ? ? ? ? ? ? f.close()

? ? ? ? ? ? ? ? print('第{}個(gè)文件保存成功'.format(image_name))

? ? ? ? else:
? ? ? ? ? ? print("第{}個(gè)文件已存在".format(image_name))

? ? ? ? pool_sema.release() ?# 解鎖imgbin-多線程-重寫run方法.py

? ? except FileNotFoundError as f:
? ? ? ? print("第{}個(gè)文件下載時(shí)遇到錯(cuò)誤,url為:{}:".format(image_name, url))
? ? ? ? print("報(bào)錯(cuò):", f)
? ? ? ? raise

? ? except TypeError as e:
? ? ? ? print("第{}個(gè)文件下載時(shí)遇到錯(cuò)誤,url為:{}:".format(image_name, url))
? ? ? ? print("報(bào)錯(cuò):", e)

最終效果是一樣的,每次啟用5個(gè)線程,完成后再啟動(dòng)下一批

 到此這篇關(guān)于Python多線程中線程數(shù)量如何控制的文章就介紹到這了,更多相關(guān)Python 線程數(shù)量控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python批量telnet檢測(cè)IP地址的端口是否開放

    python批量telnet檢測(cè)IP地址的端口是否開放

    本文主要介紹了python批量telnet檢測(cè)IP地址的端口是否開放,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • python實(shí)現(xiàn)Scrapy爬取網(wǎng)易新聞

    python實(shí)現(xiàn)Scrapy爬取網(wǎng)易新聞

    這篇文章主要介紹了python實(shí)現(xiàn)Scrapy爬取網(wǎng)易新聞,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • python讀寫csv文件實(shí)例代碼

    python讀寫csv文件實(shí)例代碼

    在本篇文章中小編給各位分享了關(guān)于python讀取和寫入csv文件的知識(shí)點(diǎn)以及實(shí)例代碼,需要的朋友們參考下。
    2019-07-07
  • Python 中對(duì) XML 文件的編碼轉(zhuǎn)換問題

    Python 中對(duì) XML 文件的編碼轉(zhuǎn)換問題

    這篇文章主要介紹了Python 中對(duì) XML 文件的編碼轉(zhuǎn)換問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • Python列表常用函數(shù)使用詳解

    Python列表常用函數(shù)使用詳解

    這篇文章主要為大家介紹了Python列表常用的一些函數(shù)的使用詳解,并通過一些簡(jiǎn)單的案例讓大家更快的理解,感興趣的可以跟隨小編一起學(xué)習(xí)一下
    2021-12-12
  • Python通過pytesseract庫實(shí)現(xiàn)識(shí)別圖片中的文字

    Python通過pytesseract庫實(shí)現(xiàn)識(shí)別圖片中的文字

    Pytesseract是一個(gè)Python的OCR庫,它可以識(shí)別圖片中的文本并將其轉(zhuǎn)換成文本形式。本文就來用pytesseract庫實(shí)現(xiàn)識(shí)別圖片中的文字,感興趣的可以了解一下
    2023-05-05
  • CentOS安裝OpenSSL1.1.1全過程

    CentOS安裝OpenSSL1.1.1全過程

    文章介紹了從頭開始編譯安裝Python3.10的步驟,包括檢查和安裝必要的依賴項(xiàng)、下載并解壓源碼、配置和編譯環(huán)境、創(chuàng)建軟連接以及配置環(huán)境變量,最后驗(yàn)證安裝是否成功
    2025-03-03
  • 關(guān)于win10在tensorflow的安裝及在pycharm中運(yùn)行步驟詳解

    關(guān)于win10在tensorflow的安裝及在pycharm中運(yùn)行步驟詳解

    這篇文章主要介紹了關(guān)于win10在tensorflow的安裝及在pycharm中運(yùn)行的步驟詳解,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Python遞歸函數(shù) 二分查找算法實(shí)現(xiàn)解析

    Python遞歸函數(shù) 二分查找算法實(shí)現(xiàn)解析

    這篇文章主要介紹了Python遞歸函數(shù) 二分查找算法實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Python實(shí)現(xiàn)動(dòng)態(tài)給類和對(duì)象添加屬性和方法操作示例

    Python實(shí)現(xiàn)動(dòng)態(tài)給類和對(duì)象添加屬性和方法操作示例

    這篇文章主要介紹了Python實(shí)現(xiàn)動(dòng)態(tài)給類和對(duì)象添加屬性和方法操作,涉及Python面向?qū)ο蟪绦蛟O(shè)計(jì)中類與對(duì)象屬性、方法的動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2020-02-02

最新評(píng)論

满城县| 赣州市| 敦煌市| 灵武市| 永康市| 西城区| 宁乡县| 龙海市| 永福县| 五河县| 浏阳市| 衡水市| 梅河口市| 山东省| 甘泉县| 宝山区| 平罗县| 汪清县| 富锦市| 珲春市| 多伦县| 通许县| 三穗县| 临澧县| 扶沟县| 土默特左旗| 彰化县| 天峻县| 定远县| 南和县| 雷波县| 镇远县| 二连浩特市| 陆丰市| 上栗县| 日喀则市| 金塔县| 石门县| 渭南市| 土默特右旗| 株洲县|