Методы многопоточного GUI update () - PullRequest
0 голосов
/ 12 мая 2019

Я новичок в многопоточности.Я недавно начал писать что-то вроде многопоточного обозревателя.Мне нужно уточнить.

Допустим, я работаю с Subject и меняю его состояние.Затем необходимо уведомить наблюдателей (в примере - виджеты с графическим интерфейсом), чтобы они могли выполнить метод update().

И вот мой вопрос : как мне справиться с этими getValue()в исполнении многих наблюдателей?Если это просто геттер для некоторой переменной, нужно ли мне запускать его в новом потоке?Требуется ли какая-либо блокировка?

Или, возможно, существует метод, позволяющий просто отправить это новое значение в поток графического интерфейса и разрешить доступ к этим значениям виджетам.И снова, это может быть один цикл, или мне нужно создать другие потоки для каждого виджета, чтобы получить эти значения?

1 Ответ

0 голосов
/ 13 мая 2019

Это сложный предмет.Вот несколько вещей, которые помогут вам в этом.

  • Примите окончательную последовательность.Когда один объект обновляется в одном потоке, другие получают уведомления об изменениях и обновляются до правильного состояния , в конечном итоге .Не пытайтесь все время синхронизировать.Не ожидайте, что все будет обновляться все время.Разработайте свою систему, чтобы справиться с этими ситуациями.Проверьте это видео.

  • Используйте неизменяемость, особенно для коллекций.Чтение и запись в коллекцию из нескольких потоков может привести к бедствиям.Не делай этого.Используйте неизменные коллекции или снимки.В основном один объект, который будет вызван из нескольких потоков, вернет моментальный снимок состояния коллекции.когда уведомление об изменении получено, читатель (в вашем случае GUI) запросит снимок нового состояния и обновит его соответствующим образом.

  • Дизайн, богатый Модели .Не используйте AnemicModels , которые имеют только setters и getters, и позволяйте другим манипулировать ими.Пусть Модель защитит свои данные и предоставит запросы для их состояния.Не возвращайте изменяемые объекты из свойств объекта.

  • Передайте данные, которые описывают изменения с уведомлениями об изменениях.Таким образом, считыватели (GUI) могут синхронизировать свое состояние только из данных изменений, не считывая целевой объект.

  • Разделить ответственность.Дайте GUI знать, что он однопоточный и получает уведомления из фона.Не добавляйте в свою модель сведения о том, что она будет обновляться в фоновом потоке, а также о том, что она вызывается из графического интерфейса, и возложите на нее ответственность за отправку запросов на изменение определенномунить.Модель не должна заботиться о подобных вещах.Это вызывает уведомления и позволяет подписчикам обрабатывать их так, как им нужно.Дайте GUI знать, что уведомление об изменении будет получено в фоновом режиме, чтобы оно могло передать его в поток пользовательского интерфейса.

Проверьте это видео .Он описывает различные способы выполнения многопоточности.

Вы не показали ни кода, ни указанного языка, поэтому я приведу пример псевдокода с использованием языка, подобного Java / C #.

public class FolderIcon {

    private Icon mIcon;

    public Icon getIcon() { return mIcon; }

    public FolderIcon(Icon icon) {
        mIcon = icon;
    }
}

public class FolderGUIElement : Observer {

    private Folder mFolder;
    private string mFolderPath;

    public FolderGUIElement(Folder folder) {

        mFolder = folder;
        mFolderPath = mFolder.getPath();

        folder.addChangeListener(this);
    }

    public void onSubjectChanged(change c) {

        if(c instanceof PathChange) {
            dispatchOnGuiThread(() => {
                handlePathChange((PathChange)change);
            });
        }
    }

    handlePathChange(PathChange change) {
        mFolderPath = change.NewPath;
    }
}

public class Folder : Subject {

    private string mPath;
    private FolderIcon mIcon;

    public string getPath() { return mPath; }

    public FolderIcon getIcon() { return mIcon; }

    public void changePath(string newPath) {
        mPath = patnewPath;
        notifyChanged(new PathChange(newPath));
    }

    public void changeIcon(FolderIcon newIcon) {
        mIcon = newIcon;
        notifyChanged(new IconChange(newIcon));
    }
}

Обратите внимание на пару вещей в примере.

  1. Мы используем неизменяемые объекты из Папка .Это означает, что элементы графического интерфейса не могут получить значение Path или FolderIcon и изменить его, влияя на Папка .При смене иконки мы создаем новый FolderIcon объект вместо изменения старого. Папка сама является изменчивой, но она использует неизменяемые объекты для своих свойств.Если вы хотите, вы можете использовать полностью неизменяемые объекты.Гибридный подход работает хорошо.

  2. Когда мы получаем уведомление об изменении, мы читаем NewPath из PathChange .Таким образом, нам не нужно снова вызывать Папка .

  3. У нас есть changePath и changeIcon методы вместо setPath и setIcon.Это лучше отражает цель наших операций и, следовательно, дает поведение модели, а не просто мешок getters и setters.

Если вы еще не прочитали Дизайн, управляемый доменом Я настоятельно рекомендую его.Речь идет не о многопоточности, а о том, как создавать богатые модели.Это в моем списке книг, которые должен прочитать каждый разработчик.По концепции в DDD это ValueObject .Он неизменен и обеспечивает отличный способ реализации моделей и особенно полезен в многопоточных системах.

...