Последствия для производительности BeginInvoke


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

Получает ли метод, вызываемый в BeginInvoke, строку сообщений, которые приходят в окно? Документы говорят asynchronously, так что это мое предположение.

Как фреймворк определяет приоритетность запуска метода, вызываемого BeginInvoke?

Правка: код выглядит вот так:

System.Action<bool> finalizeUI = delegate(bool open)
{
    try
    {
        // do somewhat time consuming stuff
    }
    finally
    {
        Cursor.Current = Cursors.Default;
    }
};

Cursor.Current = Cursors.WaitCursor;
BeginInvoke(finalizeUI, true);

Это происходит в событии Form_Load.

4 6

4 ответа:

Править

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

Вызов BeginInvoke находится внутри Form_load и не вызывается на другом объекте, поэтому это вызов Form.Начинайте призывать. Так вот что происходит.

  1. Form_Load передает делегат в форму.BeginInvoke, это помещает сообщение в очередь сообщений формы, которая находится впереди все вводимые пользователем сообщения. Он устанавливает курсор в положение ожидания.
  2. возвращается Form_Load, и остальная часть инициализации формы разрешается завершить, форма, скорее всего, становится видимой в этот момент.
  3. Как только код попадает в насос сообщений, первое, что он видит в очереди, - это делегат, поэтому он запускает его.
  4. когда делегат завершает работу, он меняет курсор обратно на обычный курсор и возвращает
  5. прибыль!

Оригинал сообщение ниже


I зависит от объекта, который вы называете BeginInvoke. Если объект является производным от Control, то управление.BeginInvoke будет выполняться в потоке, создавшем элемент управления. Увидеть JaredPar ответ.

Но есть и другой шаблон для использования BeginInvoke. если объект является делегатом, то BeginInvoke выполняет обратный вызов в отдельном потоке, который может быть создан специально для этой цели.
public class Foo
{
    ...
    public Object Bar(object arg)
    {
       // this function will run on a separate thread.
    }
}

...

// this delegate is used to Invoke Bar on Foo in separate thread, this must
// take the same arguments and return the same value as the Bar method of Foo
public delegate object FooBarCaller (object arg);

...

// call this on the main thread to invoke Foo.Bar on a background thread
//
public IAsyncResult BeginFooBar(AsyncCallback callback, object arg)
{
   Foo foo = new Foo();
   FooBarCaller caller = new FooBarCaller (foo.Bar);
   return caller.BeginInvoke (arg);
}

Эта закономерность является одной из причин того, что BeginInvoke вызывается из основного потока, а не из фонового потока.

В случае вызова BeginInvoke в потоке пользовательского интерфейса он все равно будет проходить через процесс отправки сообщения Windows в очередь сообщений, где сообщение будет ждать обработки. Делегат будет запущен после обработки сообщения. Это сообщение не имеет никакого приоритета, который отличается от вызова из фонового потока.

В этом сценарии я подозреваю, что вызов выглядит следующим образом:

private void Button1_Click(object sender, ButtonClickEventArgs e)
{
    Control.BeginInvoke(new MethodInvoker(()=> /* code etc. */));
}

Происходит то, что некоторый код будет выполняться в потоке threadpool и обновлять элемент управления в потоке, создавшем элемент управления while if Control.Был использован Invoke, некоторый код будет выполняться в потоке, создавшем элемент управления, и обновлять элемент управления в этом потоке.

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

Есть довольно хороший пример ссылки здесь в разделе "Потокобезопасные вызовы элемента управления Windows Forms".