Редактирование: Keeping the GUI Responsive

Материал из Wiki.crossplatform.ru

Перейти к: навигация, поиск
Внимание: Вы не представились системе. Ваш IP-адрес будет записан в историю изменений этой страницы.
Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.
Текущая версия Ваш текст
Строка 1: Строка 1:
-
{{Панель навигации по Qt Quarterly|Выпуск 27}}
+
__NOTOC__
-
 
+
by Witold Wysota
by Witold Wysota
<div class="introduction">
<div class="introduction">
На сайт QtCentre люди приходят с повторяющейся проблемой, их GUI перестает отвечать во время выполнения длительных операций. Эту проблему не трудно преодолеть, но вы можете сделать это по-разному, поэтому я хотел бы представить ряд возможных вариантов, которые могут быть использованы в зависимости от ситуации.
На сайт QtCentre люди приходят с повторяющейся проблемой, их GUI перестает отвечать во время выполнения длительных операций. Эту проблему не трудно преодолеть, но вы можете сделать это по-разному, поэтому я хотел бы представить ряд возможных вариантов, которые могут быть использованы в зависимости от ситуации.
-
__TOC__
+
*[[#performinglongoperations | Выполнение длительных операций]]
 +
*[[#manualeventprocessing | Manual event processing]]
 +
*[[#usingaworkerthread | Using a Worker Thread]]
 +
*[[#waitinginalocaleventloop | Waiting in a Local Event Loop]]
 +
*[[#solvingaproblemstepbystep | Solving a Problem Step by Step]]
 +
*[[#parallelprogramming | Parallel Programming]]
 +
*[[#conclusion | Conclusion]]
</div><div id="performinglongoperations"></div>
</div><div id="performinglongoperations"></div>
Строка 11: Строка 16:
Первое, что нужно сделать, это определить области проблемы и наметить пути для ее решения. Указанные проблемы могут принимать одну из двух форм. Первая, когда программа должна выполнить задачу, которая описывается как ряд операций, которые будут выполняться последовательно, с тем чтобы получить конечный результат. Примером такой задачи вычисления быстрого преобразования Фурье.
Первое, что нужно сделать, это определить области проблемы и наметить пути для ее решения. Указанные проблемы могут принимать одну из двух форм. Первая, когда программа должна выполнить задачу, которая описывается как ряд операций, которые будут выполняться последовательно, с тем чтобы получить конечный результат. Примером такой задачи вычисления быстрого преобразования Фурье.
-
Второй вариант - это когда программа должна запустить какое-то действие (например, загрузку из сети) и дождаться её  окончания перед тем, как перейти к следующему шагу алгоритма. Этот вид проблемы как таковую легко избежать используя Qt, потому что большинство асинхронных задач выполняется следующим образом: фреймворк посылает сигнал, когда задача выполнена, а вы можете привязать его к слоту, который продолжит алгоритм.
+
The second variation is when a program has to trigger some activity (for instance a network download) and wait for it to be completed before continuing to the next step of the algorithm. This variation of the problem is, in itself, easy to avoid when using Qt because most of the asynchronous tasks performed by the framework emit a signal when they have finished doing their job, and you can connect it to a slot that will continue the algorithm.
 +
 
 +
During the calculations (regardless of any usage of signals and slots) all event processing gets halted. As a result, the GUI is not refreshed, user input is not processed, network activity stops and timers don't fire&mdash;the application looks like it's frozen and, in fact, the part of it not related to the time-intensive task ''is'' frozen. How long are "long operations"? Everything that will distract the end user from interacting with the application is long. One second is long, everything longer than two seconds is definitely ''too long''.
-
Во время вычислений (независимо от использования сигналов и слотов) останавливается обработка всех событий. В результате, GUI  не обновляется, пользовательский ввод не обрабатывается, сетевая активность прекращается и таймеры не срабатывают – приложение выглядит замороженным и, фактически, та часть приложения, которая не относится к длительным вычислениям и есть заморожена. Насколько длинной должна быть «длинная операция»? Всё, что отвлекает пользователя от взаимодействия с приложением, считается долгим. Одна секунда – это долго; всё, что длиннее двух секунд определённо является «слишком долгим».
+
Our aim in this article is to keep the functionality while preventing the end user from getting irritated by a frozen GUI (and the network and timers). To do that let's take a look at possible classes of solutions and domains of the problem.
-
Цель этой статьи сохранить функциональность и в тоже время избавить пользователя от замороженного GUI (и сети, и таймеров). Чтобы сделать это, давайте взглянем на возможные классы решений и области проблем.
+
We can reach our final goal of performing calculations in one of two ways&mdash;either by doing the computation in the main thread (the ''single-threaded approach'') or in separate threads (the ''multithreaded approach''). The latter is widely known and used in the Java world, but it is sometimes abused where one thread would do the job just fine. Contrary to popular opinion, threads can often slow down your application instead of speeding it up, so unless you are sure your program can benefit from being multithreaded (either in terms of speed or simplicity), try to avoid spawning new threads simply because you can.  
-
Мы можем достичь конечной цели наших вычислений двумя путями – либо выполняя вычисления в главном потоке («однопоточный подход»), либо в отдельных потоках («многопоточных подход»). Последнее широко известно и используется в мире Java, но иногда происходит злоупотребление, когда отлично мог бы справиться и один поток. Вопреки популярному мнению, часто потоки могут замедлить ваше приложения вместо того, чтобы ускорить его. Поэтому пока вы не будете уверенны, что ваша программа может выиграть от использования многопоточности (в отношении скорости или простоты), старайтесь избегать создавать новые потоки только потому, что вы это можете.  
+
The domain of the problem can be treated as one of two cases. Either we can or cannot divide the problem into smaller parts like steps, iterations or sub-problems (usually it shouldn't be monolithic). If the task can be split into chunks, each of them can either depend on others or not. If they are independent, we can process them at any time and in arbitrary order. Otherwise, we have to synchronize our work. In the worst case, we can only do one chunk at once and we can't start the next one until the previous one is finished. Taking all these factors into consideration, we can choose from different solutions.  
-
Область проблем может рассматриваться как один из двух случаев. Мы либо можем, либо не можем разделить проблему на меньшие части, вроде шагов, итераций или подзадач (обычно проблема не должна быть монолитной). Если задача может быть разбита на кусочки, каждая из них может быть зависимой либо нет. Если они независимы, мы можем обрабатывать их в любой момент времени и в любом порядке. Иначе, мы должны будем синхронизировать нашу работу. В худшем случае, мы можем делать только один кусочек одновременно и не можем начать следующий, пока не завершится предыдущий. Приняв все эти факторы в рассмотрение, мы можем выбрать различные решения.
+
 +
<div id="manualeventprocessing"></div>
===Manual event processing===
===Manual event processing===
The most basic solution is to explicitly ask Qt to process pending events at some point in the computation. To do this, you have to call [[Qt:Документация 4.3.2//qcoreapplication#processEvents | QCoreApplication::processEvents()]] periodically. '''[[#footnote | &dagger;]]''' The following example shows how to do this:  
The most basic solution is to explicitly ask Qt to process pending events at some point in the computation. To do this, you have to call [[Qt:Документация 4.3.2//qcoreapplication#processEvents | QCoreApplication::processEvents()]] periodically. '''[[#footnote | &dagger;]]''' The following example shows how to do this:  
Строка 65: Строка 72:
      
      
     tT.setSingleShot(true);
     tT.setSingleShot(true);
-
     connect(&tT, SIGNAL(timeout()), &q, SLOT(quit()));
+
     connect(&amp;tT, SIGNAL(timeout()), &amp;q, SLOT(quit()));
-
     connect(&manager, SIGNAL(finished(QNetworkReply*)),
+
     connect(&amp;manager, SIGNAL(finished(QNetworkReply*)),
-
             &q, SLOT(quit()));
+
             &amp;q, SLOT(quit()));
     QNetworkReply *reply = manager.get(QNetworkRequest(
     QNetworkReply *reply = manager.get(QNetworkRequest(
                   QUrl("http://www.qtcentre.org")));
                   QUrl("http://www.qtcentre.org")));
Строка 85: Строка 92:
We should note two more things here. Firstly, that a similar approach is implemented in a <tt>QxtSignalWaiter</tt> class that is part of the libqxt project ([http://www.libqxt.org http://www.libqxt.org]). Another thing is that, for some operations, Qt provides a family of "wait for" methods (for example [[Qt:Документация 4.3.2//qiodevice#waitForBytesWritten | QIODevice::waitForBytesWritten()]]) that will do more or less the same as the snippet above but without running an event loop. However, the "wait for" solutions will freeze the GUI because they do not run their own event loops.
We should note two more things here. Firstly, that a similar approach is implemented in a <tt>QxtSignalWaiter</tt> class that is part of the libqxt project ([http://www.libqxt.org http://www.libqxt.org]). Another thing is that, for some operations, Qt provides a family of "wait for" methods (for example [[Qt:Документация 4.3.2//qiodevice#waitForBytesWritten | QIODevice::waitForBytesWritten()]]) that will do more or less the same as the snippet above but without running an event loop. However, the "wait for" solutions will freeze the GUI because they do not run their own event loops.
-
 
+
<div id="solvingaproblemstepbystep"></div>
===Solving a Problem Step by Step===
===Solving a Problem Step by Step===
Строка 223: Строка 230:
Never again let your GUI get frozen!
Never again let your GUI get frozen!
-
 
-
[[Категория:Qt_Издания]]
 

Пожалуйста, обратите внимание, что все ваши добавления могут быть отредактированы или удалены другими участниками. Если вы не хотите, чтобы кто-либо изменял ваши тексты, не помещайте их сюда.
Вы также подтверждаете, что являетесь автором вносимых дополнений, или скопировали их из источника, допускающего свободное распространение и изменение своего содержимого (см. Wiki.crossplatform.ru:Авторское право). НЕ РАЗМЕЩАЙТЕ БЕЗ РАЗРЕШЕНИЯ ОХРАНЯЕМЫЕ АВТОРСКИМ ПРАВОМ МАТЕРИАЛЫ!


Шаблоны, использованные на текущей версии страницы: