Ich habe eine Frage in Bezug auf die Leistung von ThreadPoolExecutor
vs Thread
Klasse für sich, die mir scheint, dass mir ein grundlegendes Verständnis fehlt.ThreadPoolExecutor vs threading.Thread
Ich habe einen Web-Scrapper in zwei Funktionen. Zuerst die Links für jedes Bild von einer Internet-Homepage und der zweiter zu analysieren, ein Bild von dem Link zu laden analysiert:
import threading
import urllib.request
from bs4 import BeautifulSoup as bs
import os
from concurrent.futures import ThreadPoolExecutor
path = r'C:\Users\MyDocuments\Pythom\Networking\bbc_images_scraper_test'
url = 'https://www.bbc.co.uk'
# Function to parse link anchors for images
def img_links_parser(url, links_list):
res = urllib.request.urlopen(url)
soup = bs(res,'lxml')
content = soup.findAll('div',{'class':'top-story__image'})
for i in content:
try:
link = i.attrs['style']
# Pulling the anchor from parentheses
link = link[link.find('(')+1 : link.find(')')]
# Putting the anchor in the list of links
links_list.append(link)
except:
# links might be under 'data-lazy' attribute w/o paranthesis
links_list.append(i.attrs['data-lazy'])
# Function to load images from links
def img_loader(base_url, links_list, path_location):
for link in links_list:
try:
# Pulling last element off the link which is name.jpg
file_name = link.split('/')[-1]
# Following the link and saving content in a given direcotory
urllib.request.urlretrieve(urllib.parse.urljoin(base_url, link),
os.path.join(path_location, file_name))
except:
print('Error on {}'.format(urllib.parse.urljoin(base_url, link)))
Der folgende Code wird in zwei Fälle aufgeteilt:
Fall 1: I verwende mehrere Threads:
threads = []
t1 = threading.Thread(target = img_loader, args = (url, links[:10], path))
t2 = threading.Thread(target = img_loader, args = (url, links[10:20], path))
t3 = threading.Thread(target = img_loader, args = (url, links[20:30], path))
t4 = threading.Thread(target = img_loader, args = (url, links[30:40], path))
t5 = threading.Thread(target = img_loader, args = (url, links[40:50], path))
t6 = threading.Thread(target = img_loader, args = (url, links[50:], path))
threads.extend([t1,t2,t3,t4,t5,t6])
for t in threads:
t.start()
for t in threads:
t.join()
Der obige Code macht seine Arbeit auf meiner Maschine für 10 Sekunden.
Fall 2: Ich bin mit ThreadPoolExecutor
with ThreadPoolExecutor(50) as exec:
results = exec.submit(img_loader, url, links, path)
Die obigen Code führt zu 18 Sekunden.
Mein Verständnis war, dass ThreadPoolExecutor
einen Thread für jeden Arbeiter erstellt. Wenn ich also max_workers
auf 50 setzen würde, würde das 50 Threads ergeben und hätte daher den Job schneller erledigt.
Kann mir bitte jemand erklären, was ich hier vermisse? Ich gebe zu, dass ich hier einen dummen Fehler mache, aber ich verstehe es einfach nicht.
Vielen Dank!
als @hansaplast bemerkte ich wurde mit nur einem Arbeiter. Also habe ich einfach meine 'img_loader' Funktion geändert, um einen einzelnen Link zu akzeptieren und dann eine' for' Schleife unter dem Kontextmanager hinzugefügt, um jeden Link in der Liste zu verarbeiten. Und es reduzierte die Zeit auf 3,8 Sekunden. – Vlad