2014-12-10 3 views
2

Я думаю, что пользовательский интерфейс не должен быть заморожен при использовании concurrent.futures.ThreadPoolExecutor здесь, но это не соответствует моим ожиданиям, кто-нибудь может объяснить, почему? любые другие решения здесь, чтобы не позволить пользователю замораживать интерфейс?пользовательский интерфейс зависает при использовании 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

Вот две вещи, которые вы должны знать:

  1. Слоты называются в потоке объекта, что означает в данном случае speedCalculate называется в главном потоке.
  2. concurrent.futures.as_completed возвращает итератор по завершенным фьючерсам, что означает, что цикл цикла над этим не завершится, пока все фьючерсы не будут завершены.

Как следствие, ваш метод 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) 
+0

И не только это, GIL предотвратит обновления пользовательского интерфейса, пока вычисление не закончено (в этом случае есть шанс, что он может идти в ногу, потому что GIL освобождается при выполнении ввода/O, как выбор URL-адресов через сеть). – kraptor

+0

Я не думаю, что проблема с GIL здесь вообще не возникает, потому что ни один интенсивный поток процессора не работает, который будет блокировать переключение потоков путем повторного запуска GIL сразу после его выпуска, а все методы python io освобождают GIL. – pankaj

+0

1) вы говорите, что слоты вызываются в потоке объекта, тогда слот соответствует завершенному() сигналу QThread в каком потоке? 2) Временное замораживание вмешательства пользователя приведет к тому, что цикл событий не будет запущен? – iMath

Смежные вопросы