Reputation: 53
I want to call and run a class in my main()
function concurrently.
I have different methods in my code that I want to run at the same time using concurrent.futures
and I figured out I could put them in a class
instead.
This is what I have tried so far:
import requests
import time
import concurrent.futures
img_urls = [
'https://images.unsplash.com/photo-1516117172878-fd2c41f4a759',
'https://images.unsplash.com/photo-1532009324734-20a7a5813719',
'https://images.unsplash.com/photo-1524429656589-6633a470097c',
'https://images.unsplash.com/photo-1530224264768-7ff8c1789d79'
]
t1 = time.perf_counter()
class Download:
def __init__(self, img_url):
self.img_url = img_url
def download_image(self, img_url):
img_bytes = requests.get(self.img_url).content
return img_bytes
def image_name(self, img_bytes):
img_bytes = download_image(self, img_url)
img_name = self.img_url.split('/')[3]
img_name = f'{img_name}.jpg'
with open(img_name, 'wb') as img_file:
img_file.write(img_bytes)
print(f'{img_name} was downloaded...')
def run(self):
download_image(self, img_url)
image_name(self, img_bytes)
def main():
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(Download, img_urls)
if __name__ == "__main__":
main()
t2 = time.perf_counter()
print(f'Finished in {t2-t1} seconds')
Upvotes: 0
Views: 79
Reputation: 21
One way to solve this problem is as Marco mentioned.
As you want to call and run using class, you can call the multithreading code from the __init__
function.
import requests
import time
import concurrent.futures
img_urls = [
"https://images.unsplash.com/photo-1516117172878-fd2c41f4a759",
"https://images.unsplash.com/photo-1532009324734-20a7a5813719",
"https://images.unsplash.com/photo-1524429656589-6633a470097c",
"https://images.unsplash.com/photo-1530224264768-7ff8c1789d79",
]
t1 = time.perf_counter()
class Download:
def __init__(self, img_url):
self.img_url = img_url
self.download_all_images()
def download_image(self, img_url):
img_bytes = requests.get(img_url, stream=True).content
return img_bytes
def image_name(self, img_url):
try:
img_bytes = self.download_image(img_url)
img_name = img_url.split("/")[3]
img_name = f"{img_name}.jpg"
print("here", img_name)
with open(img_name, "wb") as img_file:
img_file.write(img_bytes)
print(f"{img_name} was downloaded...")
except Exception as e:
print(e)
def download_all_images(self):
try:
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(self.image_name, self.img_url)
return "Success"
except:
return "Failed"
def main():
response = Download(img_urls)
print(response)
if __name__ == "__main__":
main()
t2 = time.perf_counter()
print(f"Finished in {t2 - t1} seconds")
Upvotes: 0
Reputation: 224
As I understand you want to execute the run function of different Download
objects concurrently.
The first thing is that there is a syntax error in the run function, it should be:
def run(self):
img_bytes = download_image(self, img_url)
image_name(self, img_bytes)
otherwise img_bytes
isn't defined.
Then you need to pass the correct callable to the executor. If you pass the class Download, it will only create an instance of it, not actually call the run method; to do so with every time a new instance of Download something like this should work:
executor.map(lambda url: Download(url).run, img_urls)
Upvotes: 1