用户界面在使用concurrent.futures.ThreadPoolExecutor时冻结

时间:2014-12-10 04:49:00

标签: python qt python-3.x pyqt pyside

我认为在这里使用concurrent.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_()

1 个答案:

答案 0 :(得分:1)

以下是您需要了解的两件事:

  1. 在对象的线程中调用插槽,这意味着在这种情况下,在主线程上调用speedCalculate
  2. concurrent.futures.as_completed返回完成期货的迭代器,这意味着在完成所有期货之前,for循环将无法完成。
  3. 因此,只有在完成所有下载后,您的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)