我认为在此处使用current.futures.ThreadPoolExecutor时,不应冻结用户界面,但是它不符合我的期望,任何人都可以解释原因?还有其他解决方案,不要让用户界面冻结吗?
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import time
import concurrent.futures
import urllib.request
URLS = ['http://www.tmall.com/',
'http://www.cnn.com/',
'http://huawei.com/',
'http://www.bbc.co.uk/',
'http://jd.com/',
'http://weibo.com/?c=spr_web_360_hao360_weibo_t001',
'http://www.sina.com.cn/',
'http://taobao.com',
'http://www.amazon.cn/?tag=360daohang-23',
'http://www.baidu.com/',
'http://www.pconline.com.cn/?ad=6347&360hot_site']
# Retrieve a single page and report the url and contents
def load_url(url, timeout):
conn = urllib.request.urlopen(url, timeout=timeout)
return conn.readall()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
QTimer.singleShot(3000, self.speedCalculate)
# self.timerC = QTimer();
# self.timerC.timeout.connect(self.speedCalculate)
# self.timerC.start(1000)
def speedCalculate(self):#compare with for loop
t1=time.clock()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=len(URLS)) as executor:
# Start the load operations and mark each future with its URL
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
t2=time.clock()
print('t2-t1-------------', t2-t1)
#
# for url in URLS:
# data=load_url(url, 60)
# print(url, len(data))
#
# t3=time.clock()
# print('t3-t2-------------', t3-t2)
#
if __name__ == '__main__':
app =QApplication(sys.argv)
splitter =MainWindow()
splitter.show()
app.exec_()
最佳答案
您需要了解以下两件事:
在对象的线程中调用插槽,这意味着在这种情况下,在主线程上调用speedCalculate
。concurrent.futures.as_completed
返回已完成期货的迭代器,这意味着直到所有期货都完成后,for循环才会结束。
因此,您的speedCalculate
方法仅在所有下载完成后才返回,从而阻止了应用程序事件循环。
相反,您应该做的是用另一种方法(例如speedCalculate
)在_speedCalculate
中当前执行的所有工作,然后在speedCalculate
插槽内的新线程中调用它。
就像是:
def speedCalculate(self):
threading.Thread(target=self._speedCalculate).start()
def _speedCalculate(self):#compare with for loop
t1=time.clock()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=len(URLS)) as executor:
# Start the load operations and mark each future with its URL
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
t2=time.clock()
print('t2-t1-------------', t2-t1)