Python 使程序成为多线程后,程序速度会显著降低吗?
如果我问这个问题时看起来像个傻瓜,那是因为这是我第一次尝试多线程。对不起 鉴于多线程是为了加快进程,我试图找出我在这方面的错误。我注意到的第一件事是,“主线程”线程比它应该的速度要慢得多(它是唯一一个不使用代理的线程) 在多线程进程之前,它将在一分钟内以单个进程/线程下载大约10-15个图像。但现在,“多线程”(这是唯一一个不通过代理发送HTTP请求的线程)实际上从未出现(如您所见:)。它应该是最快的线程 我希望我能把我的问题解释清楚 附言:在程序开始时,它会在15秒内下载大约20张图片;然而,在初始启动之后,程序速度急剧减慢。你知道为什么会这样吗Python 使程序成为多线程后,程序速度会显著降低吗?,python,urllib2,python-multithreading,Python,Urllib2,Python Multithreading,如果我问这个问题时看起来像个傻瓜,那是因为这是我第一次尝试多线程。对不起 鉴于多线程是为了加快进程,我试图找出我在这方面的错误。我注意到的第一件事是,“主线程”线程比它应该的速度要慢得多(它是唯一一个不使用代理的线程) 在多线程进程之前,它将在一分钟内以单个进程/线程下载大约10-15个图像。但现在,“多线程”(这是唯一一个不通过代理发送HTTP请求的线程)实际上从未出现(如您所见:)。它应该是最快的线程 我希望我能把我的问题解释清楚 附言:在程序开始时,它会在15秒内下载大约20张图片;然而,
#!/usr/bin/env python
import sys
import string
import os.path
import urllib.request
import threading
from time import gmtime, strftime, sleep
from random import choice
#list of our proxies
proxies = []
downloads = 1
#the number of files we want to download
target = int(sys.argv[1])
#argument 2 - proxies
try:
sys.argv[2]
except:
print('')
else:
param = sys.argv[2]
if param.find('.txt') != -1:
print('Loading specified proxy list ('+ param +').')
f = open(param, 'r+')
print('Opening '+ f.name)
proxylist = f.read()
f.close()
#split retrieved list by new line
proxies = proxylist.split('\n')
else:
print('Single proxy specified.')
proxies.append(param)
class thread(threading.Thread):
def __init__(self, ID, name, proxy):
threading.Thread.__init__(self)
self.id = ID
self.name = name
self.downloads = 0
self.proxy = proxy
self.running = True
self.fails = 0
def run(self):
global downloads
if self.proxy != False:
#id is always above one, so make the ID -1
self.proxy = proxies[(self.id-1)]
print(self.name +' initiating with proxy: '+self.proxy)
#make our requests go through proxy
self.p_handler = urllib.request.ProxyHandler({'http' : self.proxy})
self.opener = urllib.request.build_opener(self.p_handler)
urllib.request.install_opener(self.opener)
else:
print(self.name +' initiating without a proxy.')
while downloads <= target and self.running:
rstr = ''.join(choice(string.ascii_letters + string.digits) for x in range(5))
url = 'http://puu.sh/'+rstr
filename = 'downloaded/'+ strftime('%Y %m %d %H-%M-%S', gmtime()) +'.png';
try:
urllib.request.urlretrieve(url, filename)
except urllib.request.HTTPError:
pass
except IOError:
if self.fails > 10:
print(self.name +': Proxy is not working. Stopping thread.')
self.running = False
self.fails += 1
except:
pass
else:
print(self.name +': downloading '+ filename+'...' + str(downloads))
#if self.downloads % 10 == 0:
# print(self.name +': Sleeping a bit.')
# sleep(60)
downloads += 1
self.downloads += 1
sleep(5)
#lets create the "downloaded" folder if it does not exist
if not os.path.isdir('downloaded'):
try:
os.mkdir('downloaded')
except:
pass
#thread count
thread_count = 1
#create threads, and initiate them
try:
thread(0, 'main-thread', False).start()
for x in proxies:
thread(thread_count, 'Thread-'+str(thread_count), proxies[(thread_count-1)]).start()
thread_count += 1
except:
print('Couldn\'t start threads.')
#/usr/bin/env python
导入系统
导入字符串
导入操作系统路径
导入urllib.request
导入线程
从时间导入gmtime、strftime、sleep
从随机进口选择
#我们的代理人名单
代理=[]
下载量=1
#我们要下载的文件数
target=int(sys.argv[1])
#参数2-代理
尝试:
系统argv[2]
除:
打印(“”)
其他:
param=sys.argv[2]
如果参数find('.txt')!=-1:
打印('正在加载指定的代理列表('+param+')。)
f=打开(参数“r+”)
打印('期初'+f.name)
proxylist=f.read()
f、 关闭()
#按新行拆分检索到的列表
代理=proxylist.split('\n')
其他:
打印('指定了单个代理')
proxies.append(参数)
类线程(threading.thread):
定义初始化(self、ID、name、proxy):
threading.Thread.\uuuuu init\uuuuuu(自)
self.id=id
self.name=名称
self.downloads=0
self.proxy=proxy
self.running=True
self.fails=0
def运行(自):
全球下载
如果self.proxy!=错误:
#id始终大于1,因此将id设为-1
self.proxy=代理[(self.id-1)]
打印(self.name+'使用代理启动:'+self.proxy)
#让我们的请求通过代理
self.p_handler=urllib.request.ProxyHandler({'http':self.proxy})
self.opener=urllib.request.build\u opener(self.p\u处理程序)
urllib.request.install_opener(self.opener)
其他:
打印(self.name+“无代理启动”。)
同时下载10:
打印(self.name+':代理不工作。正在停止线程。“)
self.running=False
self.fails+=1
除:
通过
其他:
打印(self.name+':下载“+filename+'…”+str(下载))
#如果self.downloads%10==0:
#打印(self.name+':睡一会儿)
#睡眠(60)
下载次数+=1
self.downloads+=1
睡眠(5)
#如果“已下载”文件夹不存在,让我们创建它
如果不是os.path.isdir(“已下载”):
尝试:
os.mkdir('已下载')
除:
通过
#线程数
线程计数=1
#创建线程,并启动它们
尝试:
线程(0,'主线程',False).start()
对于代理中的x:
线程(线程计数,'thread-'+str(线程计数),代理[(线程计数-1)])。开始()
线程计数+=1
除:
打印('无法启动线程')
我不知道实际的问题是什么,但我注意到一件事是您使用了urllib.request.install\u opener
。这将设置一个默认的全局开启器,因此每个线程都将看到更改。很可能在第一次执行时,大多数线程都会使用分配给它们的代理,但在这之后,所有请求都会转到同一个代理,而您会被代理或其他什么限制
睡眠(5)看起来很奇怪。这很容易成为你的问题
您正在使用没有锁定的共享全局变量。在大多数情况下,它可能不会对您造成影响,但最终您可能会遇到奇怪的失败,除非您正确地同步来自不同线程的对可变状态的所有同步访问。他正在下载URL,因此他是io绑定的。但是,通过并行进行,他应该会更快。在python中,由于Gil,多线程在CPU受限时没有帮助。@VaughnCato多线程在I/O受限时应该有帮助,而不是相反。@mr2ert:多线程如何让他在internet连接上获得更多带宽?@VaughnCato:在python中,多线程实际上往往不会帮助CPU受限的程序,因为它的。对于此类问题,建议使用。建议使用螺纹连接。它不会增加您的带宽,但如果您不能充分利用串行请求的连接,并行请求可能会更快。@VaughnCato我不是说它是。一般的经验法则是,多线程实际上会减慢CPU限制的任务(如计算素数等)。这是因为GIL。是的,但它仍然会使线休眠。你真的想这么做吗?它只有在成功下载图像后才会休眠。睡眠是否是一个问题取决于线程的数量和下载的大小。但是5秒是很多。