我认为在此处使用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)

10-06 08:40