It occurs to me that the easiest thing you can do is to try to use the class
Pool of the module
from multiprocessing import Pool
# Acá va tu magia para subir los archivos
images_full_path = [...] # Tus archivos
pool = Pool()
What you are going to do is, for each element in
images_full_path apply the function
upload_to_s3 . In this function the code must be to upload to S3 as you have been doing.
Pool uses a certain number of "workers" to run the job in parallel. If you do not explicitly pass the number of "workers" will use the number of CPUs.
It does not use threads, but it may be useful to begin with.