python - 在Python中使用多线程下载大量文件,少数文件“滞后”
问题描述
我正在使用多线程从 Python 中的同一服务器下载大量文件。例如,更具体地说,我尝试使用 12 个线程同时下载 12 个文件。我注意到 10 个文件的下载速度相对较快,而 2 个则滞后。即使这 10 个文件下载完成,其他 2 个文件的下载速度也很慢。如果我再尝试下载这两个文件,速度会好很多。那么到底发生了什么,我该如何解决呢?
PS:我尝试将线程数减少到 8,因此同时下载了 8 个文件,而我有 1 个文件再次滞后于其余文件。
PPS:然后我尝试减少到 6 个线程,同样的问题。一个文件会滞后。如果我直接从 Firefox 下载,我没有这个问题,而且我得到了显着的加速,但我正在尝试自动化这个过程,所以从 Firefox 下载不是一个选项。
作为参考,下面是代码:
import queue
import threading
import time
start = time.perf_counter()
class MyThread(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
print('Starting thread %s.' % self.name)
process_queue()
print('Exiting thread %s.' % self.name)
def process_queue():
while True:
try:
url = my_queue.get(block=False)
filename = url.split('/')[-1]
with closing(request.urlopen(url)) as r:
with open(filename, 'wb') as f:
shutil.copyfileobj(r, f)
except queue.Empty:
return
# setting up variables
urls = [
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/000/SRR8240860/SRR8240860_1.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/000/SRR8240860/SRR8240860_2.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/001/SRR8240861/SRR8240861_1.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/001/SRR8240861/SRR8240861_2.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/002/SRR8240862/SRR8240862_1.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/002/SRR8240862/SRR8240862_2.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/003/SRR8240863/SRR8240863_1.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/003/SRR8240863/SRR8240863_2.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/004/SRR8240864/SRR8240864_1.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/004/SRR8240864/SRR8240864_2.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/005/SRR8240865/SRR8240865_1.fastq.gz',
'ftp://ftp.sra.ebi.ac.uk/vol1/fastq/SRR824/005/SRR8240865/SRR8240865_2.fastq.gz',
]
# filling the queue
my_queue = queue.Queue()
for url in urls:
my_queue.put(url)
# initializing and starting num_threads threads
num_threads = 8
threads = []
for i in range(num_threads):
thread = MyThread(i)
threads.append(thread)
for thread in threads:
thread.start()
for thread in threads:
thread.join()
finish = time.perf_counter()
print(f'Finished in {round(finish-start, 2)} second(s)')