Насколько дорог IsInvokeRequired - PullRequest
2 голосов
/ 26 марта 2009

Есть ли документация о том, сколько именно это стоит:

if (x.IsInvokeRequired)
{
    beginInvoke . . . .
}
  • Если у вас есть случай, когда 90% времени находится в фоновом потоке (и, следовательно, требуется), это того стоит?
  • Если у вас есть случай, когда 90% времени находится в потоке пользовательского интерфейса (и, следовательно, не требуется), оно того стоит?

Любые метрики вокруг этого были бы хороши.

Ответы [ 3 ]

5 голосов
/ 26 марта 2009

Реальный ответ:

Используйте профилировщик

Нечеткий ответ:

Я думаю, вам нужно учитывать относительную стоимость обеих функций и абсолютную стоимость InvokeRequired.

InvokeRequired for Control по существу сравнивает текущий ThreadId с ожидаемым ThreadId. Если вы посмотрите на рефлектор, код будет немного сложнее, но на самом деле это то, что он делает. Это довольно дешево, так как это всего лишь несколько вызовов функций и сравнение.

BeginInvoke включает в себя несколько блокировок, добавление делегатов в очередь вызова и, возможно, маршала между потоками. Этот код намного дороже по сравнению с реальным вызовом InvokeRequired (вероятно, на порядок или 2). Вам потребуется гораздо больше вызовов, когда InvokeRequired возвращает значение true, прежде чем вы увидите какую-либо выгоду, просто перейдя прямо к BeignInvoke.

3 голосов
/ 26 марта 2009

Нет метрик, но быстрый переход в Reflector говорит нам о том, что вызов, скорее всего, совсем не дорогой:

[SRDescription("ControlInvokeRequiredDescr"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public bool InvokeRequired
        {
            get
            {
                using (new MultithreadSafeCallScope())
                {
                    HandleRef ref2;
                    int num;
                    if (this.IsHandleCreated)
                    {
                        ref2 = new HandleRef(this, this.Handle);
                    }
                    else
                    {
                        Control wrapper = this.FindMarshalingControl();
                        if (!wrapper.IsHandleCreated)
                        {
                            return false;
                        }
                        ref2 = new HandleRef(wrapper, wrapper.Handle);
                    }
                    int windowThreadProcessId = SafeNativeMethods.GetWindowThreadProcessId(ref2, out num);
                    int currentThreadId = SafeNativeMethods.GetCurrentThreadId();
                    return (windowThreadProcessId != currentThreadId);
                }
            }
        }

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

2 голосов
/ 26 марта 2009

Стоимость InvokeRequired зависит от того, какой класс реализует ISynchronizeInvoke, и от конкретного случая использования. «Стоимость» будет сильно зависеть от используемой вами реализации. Однако, как правило, это довольно низкие накладные расходы. (Во многих случаях это может быть так же просто, как проверить, совпадает ли текущий поток с исходным потоком.)

Это, как говорится, если вам это нужно, это стоит затрат, ВСЕГДА. Даже если это только 1% времени, которое потребуется, оно должно быть включено. В противном случае вы запрашиваете сбой, блокировку или другое нежелательное поведение. В большинстве случаев, когда вы могли бы использовать это, вы должны всегда включать эту стоимость.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...