Invoke и BeginInvoke
Привет,
Я разрабатываю некоторые приложения в С#. На данный момент я занимаюсь резьбой, и у меня есть вопрос, который у меня на уме.
В чем разница между Invoke и BeginInvoke?
Я прочитал несколько статей, и я нашел здесь полезную информацию: здесь
Какая разница между Invoke и BeginInvoke в следующем коде:
private void ProcessRoutine()
{
for (int nValue = StartFrom; nValue <= EndTo; nValue++)
{
this.Invoke(this.MyDelegate, nValue);
//this.BeginInvoke(this.MyDelegate, nValue);
}
MessageBox.Show("Counting complete!");
}
private void MessageHandler(int progress)
{
lblStatus.Text = lblStatus.Text = "Processing item: " + progress.ToString();
progressBar1.Value = progress;
}
где MyDelegate является ссылкой на функцию MessageHandler.
Я заметил, что использование BeginInvoke lblStatus.Text не обновляется, когда использование Invoke обновляет метку.
Кроме того, я знаю, что Invoke ждет завершения его выполнения.
Самый важный случай, который меня интересует, - это то, почему в этом случае есть разница в освещении текста ярлыка.
Ответы
Ответ 1
С помощью Invoke метод запускается, и приложение ожидает его завершения.
С BeginInvoke метод вызывается Asychnronously, и приложение продолжает выполняться, пока выполняется метод, указанный в BeginInvoke.
С BeginInvoke вам нужно вызвать EndInvoke, чтобы получить результаты метода, который вы выполнили, с помощью BeginIvnoke.
Вы не должны обновлять компоненты GUI в методах BeginXXX, поскольку они выполняются в другом потоке в потоке графического интерфейса, в отличие от вашего метода Invoke. Вы не можете обращаться к компонентам графического интерфейса в другом потоке в поток графического интерфейса.
Надеюсь, это поможет!
Ответ 2
Начнем с вашей ссылки:
-
Control.Invoke
: Выполняется в потоке пользовательского интерфейса, но вызов продолжается до завершения.
-
Control.BeginInvoke
: выполняется в асинхронном потоке пользовательского интерфейса, а вызывающий поток не ждет завершения.
и из MSDN:
BeginInvoke выполняет асинхронный заданный делегат в потоке, на котором был создан управляющий базовый дескриптор.
Подводя итог, BeginInvoke
является асинхронным. Когда BeginInvoke
вызывается из потока пользовательского интерфейса, запрос будет выполняться параллельно с потоком пользовательского интерфейса. Это означает, что он не может выполняться до тех пор, пока не вернется текущий исполняемый метод. Поэтому в этом случае текстовое поле никогда не будет обновляться, поскольку цикл for не будет прерван, так как вызывающий поток не будет ждать завершения этого события, прежде чем продолжить.
В качестве альтернативы, Invoke
является синхронным. Текстовое поле будет обновлено, потому что вызывающий поток будет ждать завершения вызова перед продолжением выполнения.
Ответ 3
Control.BeginInvoke
не работает на другой поток (или threadpool), делегат .BeginInvoke делает. MSDN один слот говорит:
Выполняет указанный делегат асинхронно по потоку, что контрольная базовая ручка была создано на.
Однако Control.BeginInvoke
просто использует PostMessage и возвращает - не создается CLR Thread
.
В функции PostMessage (сообщений) сообщение в очереди сообщений связанные с потоком, который создал указанное окно и возвращает, не дожидаясь потока для обработки сообщения.
В этой статье содержится краткая информация о том, следует ли использовать Invoke
или BeginInvoke
достаточно хорошо:
Какую функцию использовать, спросите вы. Это действительно зависит от вашего требования. Если вы хотите, чтобы ваше обновление пользовательского интерфейса завершалось перед продолжением вы используете Invoke. Если нет такого требования, я бы предложите использовать BeginInvoke, поскольку это делает поток, называющий это, казалось бы, "Быстрее". Есть несколько с BeginInvoke, хотя.
- Если функция, которую вы вызываете через BeginInvoke, получает доступ к общему состоянию (состояние, разделяемое между потоком пользовательского интерфейса и другие потоки), вы находитесь в беда. Государство может измениться между тем, как вы позвонили BeginInvoke и когда завернутый функция фактически выполняется, что приводит к трудно найти проблемы с сроками.
- Если вы передаете ссылочные параметры функции, вызванной через BeginInvoke, тогда вы должны убедиться что никто другой не изменяет пройденный объект до завершения функции. Обычно люди клонируют объект прежде чем передать его BeginInvoke, что позволяет избежать проблемы в целом.
Ответ 4
BeginInvoke выполняет тело метода в другом потоке и позволяет продолжить поток. Если вы пытаетесь напрямую обновить свойство управления из другого потока, оно выдает исключение.
Ответ 5
Это в основном сводится к тому, хотите ли вы, чтобы элемент управления обновлялся синхронно или асинхронно. Все это зависит от вашей конкретной ситуации.