Препятствуйте тому, чтобы UI заморозился без дополнительных потоков

Преимущества:

  • Может генерировать их офлайн.
  • Делает репликацию тривиальной (в противоположность интервалу, который делает ее ДЕЙСТВИТЕЛЬНО трудно)
  • ORM's обычно как они
  • Уникальный через приложения. Таким образом, Мы можем использовать PK от нашего CMS (гуид) в нашем приложении (также гуид) и знать, что никогда не собираемся получать столкновение.

Недостатки:

  • Большее использование пространства, но пространство является дешевым (er)
  • , не Может заказать идентификатором для получения порядка вставки.
  • Может выглядеть ужасным в URL, но действительно, WTF, Вы делающий помещение РЕАЛЬНОГО DB вводите URL!?
  • Тяжелее, чтобы сделать ручную отладку, но не настолько трудно.

Лично, я использую их для большей части PK в любой системе достойного размера, но я был "обучен" на системе, которая копировалась повсеместно, таким образом, у нас должны были быть они. YMMV.

я думаю, что дублирующейся вещью данных является мусор - можно получить дублирующиеся данные однако, Вы делаете это. Суррогатные ключи обычно осуждаются, где когда-либо я работал. Мы ДЕЙСТВИТЕЛЬНО используем подобную Wordpress систему хотя:

  • уникальный идентификатор для строки (GUID/независимо от того, что). Никогда видимый пользователю.
  • общедоступный идентификатор сгенерирован ОДНАЖДЫ от некоторого поля (например, заголовок - делают его the-title-of-the-article)

ОБНОВЛЕНИЕ: , Таким образом, этот получает +1'ed много, и я думал, что должен указать на большую оборотную сторону GUID PK: Кластерные индексы.

, Если у Вас есть много записей и кластерный индекс на GUID, Ваша производительность вставки ВЫСОСЕТ, поскольку Вы добираетесь, вставляет в случайные места в списке объектов (thats точка), не в конце (который быстр)

Поэтому, если Вы должны вставить производительность, возможно, используйте auto-inc INT и генерируйте GUID, если Вы хотите совместно использовать его с кем-то еще (т.е., покажите его пользователю в URL)

6
задан luvieere 29 October 2009 в 16:17
поделиться

6 ответов

If you only use a single thread then the UI will freeze while you do any amount of processing.

If you use a BackgroundWorker thread you'll have more control over what happens & when.

To update the UI you need to use Dispatcher.Invoke from your background thread to marshal the call across the thread boundary.

Dispatcher.Invoke(DispatcherPriority.Background,
                  new Action(() => this.TextBlock.Text = "Processing");
12
ответ дан 8 December 2019 в 13:47
поделиться

Вы можете перевернуть поток управления с ног на голову с помощью DispatcherFrames, позволяя десериализации выполняться в потоке пользовательского интерфейса в фоновом режиме.

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

Каждый раз, когда вы получаете управление, все, что вам нужно сделать, это:

  1. Создать DispatcherFrame
  2. Поставить в очередь событие диспетчеру, используя BeginInvoke, который устанавливает Continue = false на фрейме
  3. Используйте PushFrame, чтобы запустить фрейм в Dispatcher

. Кроме того, при вызове самого десериализатора убедитесь, что вы делаете это из Dispatcher.BeginInvoke, или что ваш вызывающий код не содержит блокировок и т. д.

Вот как это будет выглядеть:

  public partial class MyWindow
  {
    SomeDeserializer _deserializer = new SomeDeserializer();

    byte[] _sourceData;
    object _deserializedObject;

    ...

    void LoadButton_Click(...)
    {
      Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
      {
        _deserializedObject = _deserializer.DeserializeObject(_sourceData);
      }));
    }
  }

  public class OneOfTheObjectsBeingDeserializedFrequently
  {
    ...

    public string SomePropertyThatIsFrequentlySet
    {
      get { ... }
      set { ...; BackgroundThreadingSolution.DoEvents(); }
    }
  }

  public class BackgroundThreadingSolution
  {
    [ThreadLocal]
    static DateTime _nextDispatchTime;

    public static void DoEvents()
    {
      // Limit dispatcher queue running to once every 200ms
      var now = DateTime.Now;
      if(now < _nextDispatchTime) return;
      _nextDispatchTime = now.AddMilliseconds(200);

      // Run the dispatcher for everything over background priority
      var frame = new DispatcherFrame();
      Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
      {
        frame.Continue = false;
      }));
      Dispatcher.PushFrame(frame);
    }
  }

Проверка DateTime.Now в DoEvents () на самом деле не требуется для работы этого метода, но повысит производительность, если SomeProperty устанавливается очень часто во время десериализации.

Edit: Сразу после того, как я написал это, я понял, что есть более простой способ реализовать метод DoEvents. Вместо использования DispatcherFrame просто используйте Dispatcher.Invoke с пустым действием:

    public static void DoEvents()
    {
      // Limit dispatcher queue running to once every 200ms
      var now = DateTime.Now;
      if(now < _nextDispatchTime) return;
      _nextDispatchTime = now.AddMilliseconds(200);

      // Run the dispatcher for everything over background priority
      Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => {}));
    }
2
ответ дан 8 December 2019 в 13:47
поделиться

Вот замечательная запись в блоге от Dwane Need , в которой обсуждаются все доступные варианты работы с элементами пользовательского интерфейса между несколькими потоками.

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

2
ответ дан 8 December 2019 в 13:47
поделиться

Вы по-прежнему можете выполнять долгую обработку в отдельном потоке, но по завершении вам необходимо синхронизироваться с потоком пользовательского интерфейса, вызвав Dispatcher.BeginInvoke (your_UI_action_here)

0
ответ дан 8 December 2019 в 13:47
поделиться

Рекомендации из блога OldNewThing.

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

Итак, One GUI Thread Многие рабочие потоки, которые выполняют эту работу.

Если какой-либо из ваших потоков все же зависает, пользователь, имеющий прямой контроль над вашим приложением, может закрыть поток, не влияя на его опыт работы с интерфейсом приложения. Это сделает его счастливым, потому что ваш пользователь будет чувствовать, что все под контролем, кроме того, что он постоянно нажимает ЭТУ КНОПКУ СТОП, И ПОИСК НЕ ПРЕКРАЩАЕТСЯ.

0
ответ дан 8 December 2019 в 13:47
поделиться

Попробуйте заморозить ваши UIElements. Замороженные объекты могут передаваться между потоками, не встречая InvalidOperationException, поэтому вы десериализуете их и замораживаете их в фоновом потоке, прежде чем использовать их в своем потоке пользовательского интерфейса.

В качестве альтернативы, рассмотрите возможность отправки отдельных десериализаций обратно в поток пользовательского интерфейса с приоритетом фона. Это не оптимально, поскольку поток пользовательского интерфейса по-прежнему должен выполнять всю работу по десериализации этих объектов, и есть некоторые накладные расходы, добавляемые путем отправки их как отдельных задач, но, по крайней мере, вы не будете блокировать пользовательский интерфейс - события с более высоким приоритетом, такие как ввод можно будет перемежать с вашей работой по десериализации с более низким приоритетом.

0
ответ дан 8 December 2019 в 13:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: