首先因为工作原因,批量下载很常见,之前一直也没太关注这一块,但是闲下来对这个块的确有点感兴趣,
于是在实验中试着进行一些操作,本文主要探讨,异步,单线程,多线程,以及多进程的情况下,图片
下载速度的问题。
代码部分使用的python
,如果有什么不对的地方欢迎指出,一同进步。
首先准备了100个图片链接的列表,这里因为数据源的问题就不透露了。
单线程示例:
最普通的方式,没什么好说的。
def main():
targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
if not os.path.isdir(targetDir): # 不存在创建路径
os.makedirs(targetDir)
num = 0
for i in _list:
downloadImage(i, targetDir, num)
num = num + 1
def downloadImage(img_url,fileDir,fileName):
r = requests.get(img_url, headers)
t = os.path.join(fileDir, str(fileName) + '.jpg') # 指定目录
fw = open(t, 'wb') # 指定绝对路径
fw.write(r.content) # 保存图片到本地指定目录
if __name__ == '__main__':
start = time.clock()
main()
end = time.clock()
print("程序运行时间:" + str(end - start))
多线程(第一版)
最普通的多线程,一个请求一个线程。
def main():
targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
if not os.path.isdir(targetDir): # 不存在创建路径
os.makedirs(targetDir)
num = 0
for i in _list:
t =threading.Thread(target=downloadImage, args=(i, targetDir, num))
t.start()
t.join()
num = num + 1
def downloadImage(img_url,fileDir,fileName):
r = requests.get(img_url, headers)
t = os.path.join(fileDir, str(fileName) + '.jpg') # 指定目录
fw = open(t, 'wb') # 指定绝对路径
fw.write(r.content) # 保存图片到本地指定目录
if __name__ == '__main__':
start = time.clock()
main()
end = time.clock()
print("程序运行时间:" + str(end - start))
多线程(第二版)
使用了线程池的方式.好像明白了为什么很少人这么玩。
def main():
targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
if not os.path.isdir(targetDir): # 不存在创建路径
os.makedirs(targetDir)
num = 0
pool = threadpool.ThreadPool(10)
for i in _list:
dict_vars_1 = {'img_url': i, 'fileDir': targetDir, 'fileName': num}
func_var = [(None, dict_vars_1)]
requests = threadpool.makeRequests(downloadImage, func_var)
[pool.putRequest(req) for req in requests]
pool.wait()
num = num + 1
def downloadImage(img_url,fileDir,fileName):
r = requests.get(img_url, headers)
t = os.path.join(fileDir, str(fileName) + '.jpg') # 指定目录
fw = open(t, 'wb') # 指定绝对路径
fw.write(r.content) # 保存图片到本地指定目录
if __name__ == '__main__':
start = time.clock()
main()
end = time.clock()
print("程序运行时间:" + str(end - start))
多进程(第一版)
一次下载起一个进程,起进程开销大实则体验不好。
def main():
targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
if not os.path.isdir(targetDir): # 不存在创建路径
os.makedirs(targetDir)
num = 0
for i in _list:
p = Process(target=downloadImage, args=(i,targetDir,num))
p.start()
p.join()
num = num + 1
def downloadImage(img_url,fileDir,fileName):
r = requests.get(img_url, headers)
t = os.path.join(fileDir, str(fileName) + '.jpg') # 指定目录
fw = open(t, 'wb') # 指定绝对路径
fw.write(r.content) # 保存图片到本地指定目录
if __name__ == '__main__':
start = time.clock()
main()
end = time.clock()
print("程序运行时间:" + str(end - start))
多进程第二版
可以说,非常快了,只起了四个进程,减少了很多开销,速度的确得到了飞升。
def main():
targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
if not os.path.isdir(targetDir): # 不存在创建路径
os.makedirs(targetDir)
num = 0
p = Pool(4)
for i in _list:
p.apply_async(downloadImage, args=(i,targetDir,num,))
num = num + 1
p.close()
p.join()
def downloadImage(img_url,fileDir,fileName):
r = requests.get(img_url, headers)
t = os.path.join(fileDir, str(fileName) + '.jpg') # 指定目录
fw = open(t, 'wb') # 指定绝对路径
fw.write(r.content) # 保存图片到本地指定目录
if __name__ == '__main__':
start = time.clock()
main()
end = time.clock()
print("程序运行时间:" + str(end - start))
异步
基础的异步,没啥好介绍的
def main():
targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
if not os.path.isdir(targetDir): # 不存在创建路径
os.makedirs(targetDir)
num = 0
loop = asyncio.get_event_loop()
for i in _list:
loop.run_until_complete(downloadImage(i, targetDir, num))
num = num + 1
async def downloadImage(img_url,fileDir,fileName):
r = requests.get(img_url, headers)
t = os.path.join(fileDir, str(fileName) + '.jpg') # 指定目录downloadImage
fw = open(t, 'wb') # 指定绝对路径
fw.write(r.content) # 保存图片到本地指定目录
if __name__ == '__main__':
start = time.clock()
main()
end = time.clock()
print("程序运行时间:" + str(end - start))
异步(第二版)
有大佬指出上面的写法,不标准,于是加了一个版本。
async def main():
targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test\\renran")
if not os.path.isdir(targetDir): # 不存在创建路径
os.makedirs(targetDir)
num = 0
for i in _list:
await downloadImage(i, targetDir, num)
num = num + 1
async def downloadImage(img_url,fileDir,fileName):
r = requests.get(img_url, headers)
t = os.path.join(fileDir, str(fileName) + '.jpg') # 指定目录downloadImage
fw = open(t, 'wb') # 指定绝对路径
fw.write(r.content) # 保存图片到本地指定目录
if __name__ == '__main__':
start = time.clock()
loop = asyncio.get_event_loop()
tasks = [main()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
end = time.clock()
print("程序运行时间:" + str(end - start))
测验总结
版本 | 数量 | 时间/s | 点评 |
---|---|---|---|
单线程 | 1 | 58.6002 | 中规中矩的玩法,可能是大部分人程序的速度。 |
多线程 | 100 | 14.4361 | 看的出来的优化速度,经常能看到的同事写法。 |
多线程(线程池) | 4 | 12.7496 | 这个玩法写的人很少,但是速度的确比开全量线程要快一丢丢(然并卵)。 |
_ | 10 | 18.5659 | ↑ |
_ | 50 | 21.3403 | ↑ |
多进程 | 100 | 72.7953 | 由此可见,进程开销是真的很大,某种程度还不如单线程呢(强行优化真的会打脸)。 |
多进程(进程池) | 4 | 5.6596 | 这是什么神仙速度,如果你体验了你会爱上它.在控制一定的数量下,它会表现更加优异! |
_ | 10 | 2.9305 | ↑ |
_ | 50 | 7.6447 | ↑ |
异步 | 1 | 23.1643 | 老实说,异步了也还是单线程的本质,不过这个效率已经比较满意了。 |
异步(第二版) | 1 | 13.0175 | 这种异步的方式,会更快了一些。 |
福利时间:
好了,今天的内容就到这里啦,如果你有更好的测验想法,欢迎在下方评论,留言。
如果有错误的地方欢迎指正,谢谢!
以上完毕!