Последствия для производительности 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 ответа:
Править
Теперь, когда мы видим код, ясно, что это просто способ переместить некоторую инициализацию из Form_Load, но все же это произойдет до того, как пользователь сможет взаимодействовать с формой.
Вызов
BeginInvoke
находится внутри Form_load и не вызывается на другом объекте, поэтому это вызов Form.Начинайте призывать. Так вот что происходит.
- Form_Load передает делегат в форму.BeginInvoke, это помещает сообщение в очередь сообщений формы, которая находится впереди все вводимые пользователем сообщения. Он устанавливает курсор в положение ожидания.
- возвращается Form_Load, и остальная часть инициализации формы разрешается завершить, форма, скорее всего, становится видимой в этот момент.
- Как только код попадает в насос сообщений, первое, что он видит в очереди, - это делегат, поэтому он запускает его.
- когда делегат завершает работу, он меняет курсор обратно на обычный курсор и возвращает
- прибыль!
Оригинал сообщение ниже
I зависит от объекта, который вы называете BeginInvoke. Если объект является производным от
Но есть и другой шаблон для использования BeginInvoke. если объект является делегатом, то BeginInvoke выполняет обратный вызов в отдельном потоке, который может быть создан специально для этой цели.Control
, то управление.BeginInvoke будет выполняться в потоке, создавшем элемент управления. Увидеть JaredPar ответ.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".