Яка різниця між Invoke () та BeginInvoke ()


398

Просто цікаво, в чому різниця між собою BeginInvoke()і якими Invoke()є?

Головним чином, для чого кожен би використовувався.

EDIT: Яка різниця між створенням об'єкта потоку та викликом виклику на ньому та просто запрошенням BeginInvoke()делегата? чи вони однакові?

Відповіді:


568

Ви маєте на увазі Delegate.Invoke/ BeginInvokeабо Control.Invoke/ BeginInvoke?

  • Delegate.Invoke: Виконується синхронно, на одній темі.
  • Delegate.BeginInvoke: Виконує асинхронно на threadpoolпотоці.
  • Control.Invoke: Виконується на потоці користувальницького інтерфейсу, але виклик потоку очікує завершення перед продовженням.
  • Control.BeginInvoke: Виконується на потоці користувальницького інтерфейсу, а потік виклику не чекає завершення.

У відповіді Тіма згадується, коли ви хочете скористатися, BeginInvoke- Delegate.BeginInvokeпідозрюю, що це, головним чином, спрямоване на це.

Для програм Windows Forms я б запропонував вам зазвичай використовувати BeginInvoke. Таким чином, вам не потрібно турбуватися про тупик, наприклад, - але ви повинні розуміти, що інтерфейс користувача не міг оновлюватися до наступного перегляду! Зокрема, ви не повинні змінювати дані, які нитка інтерфейсу користувача збирається використовувати для відображення. Наприклад, якщо у вас є Personз FirstNameі LastNameвластивостями, і ви зробили:

person.FirstName = "Kevin"; // person is a shared reference
person.LastName = "Spacey";
control.BeginInvoke(UpdateName);
person.FirstName = "Keyser";
person.LastName = "Soze";

Тоді інтерфейс може відобразити "Keyser Spacey". (Є ймовірний зовнішній вигляд, що він міг би відображати "Кевін Созе", але лише через дивацтво моделі пам'яті.)

Якщо у вас немає подібних питань, однак, Control.BeginInvokeлегше виправитись, і уникнете того, що ваш фоновий потік не доведеться чекати без поважних причин. Зауважте, що команда Windows Forms гарантувала, що ви можете користуватися Control.BeginInvoke"вогнем і забути", тобто без жодного дзвінка EndInvoke. Це не стосується асинхронних викликів взагалі: зазвичай кожен BeginXXX повинен мати відповідний виклик EndXXX, як правило, у зворотному дзвінку.


4
Тоді навіщо ppl використовувати Invoke над BeingInvoke? Чи не повинно бути певних переваг перед використанням Invoke. Обидва виконують процеси у фоновому режимі, просто той, що знаходиться на одній нитці, а інший на іншій нитці?
yeeen

2
@Jon: Хоча я використовую Dispatcher.BeginInvoke, мій код працює нормально, і в Dispatcher.Invoke моя програма змушує мене почекати кілька секунд, потім вона ініціалізує всі елементи керування, а потім запустить. ?
SharpUrBrain

6
@SharpUrBrain: Control.BeginInvoke є свого роду еквівалентом Dispatcher.BeginInvoke, але для WinForms (тоді як Dispatcher призначений для WPF та Silverlight).
Джон Скіт

4
@SharpUrBrain: Я б запропонував вам задати конкретне запитання, а не продовжувати коментарі, - і звичайно перевірити, чи це ж питання вже задав хтось інший.
Джон Скіт

2
@AZ: Так, "під потоком користувальницького інтерфейсу" він має на увазі конкретний "потік користувальницького інтерфейсу", якому належить ця ручка управління. Як правило, є лише один потік інтерфейсу, але можливо мати декілька потоків інтерфейсу, і в розширених програмах є причини, чому ви хотіли б їх. Технічно будь-який (нормальний?) Потік може запустити насос повідомлення UI та стати потоком UI - і пізніше може вимкнути насос повідомлення і більше не бути потоком інтерфейсу. (Я припускаю, що це не те, що приміряти на різьблення з нитки.)
Роб Паркер

46

Спираючись на відповідь Джона Скіта, є випадки, коли ви хочете викликати делегата і чекати його завершення до продовження поточного потоку. У цих випадках дзвінок Invoke - це те, що ви хочете.

У програмах з багатопотоковою передачею, можливо, ви не хочете, щоб потік чекав на делегата, щоб закінчити виконання, особливо якщо цей делегат виконує введення / виведення (що може зробити делегат і блок потоку).

У таких випадках було б корисно BeginInvoke. Зателефонувавши до цього, ви говорите делегату почати, але тоді ваша нитка може робити інші речі паралельно з делегатом.

Використання BeginInvoke збільшує складність вашого коду, але бувають випадки, коли покращена продуктивність коштує складності.


27

Різниця між Control.Invoke()і Control.BeginInvoke()є,

  • BeginInvoke()планує асинхронну дію на потоці GUI. Коли запланована асинхронна дія, ваш код продовжується. Через деякий час (ви точно не знаєте, коли) буде виконана ваша асинхронна дія
  • Invoke() виконає вашу асинхронну дію (на нитці GUI) і чекатиме завершення вашої дії.

Логічний висновок полягає в тому, що делегат, якому ви передаєте, Invoke()може мати параметри або значення, що повертаються, а делегат, якому ви BeginInvoke()передаєте, не може (для отримання результатів потрібно використовувати EndInvoke).


20

Просто навести короткий, робочий приклад, щоб побачити ефект їх різниці

new Thread(foo).Start();

private void foo()
{
  this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
    (ThreadStart)delegate()
    {
        myTextBox.Text = "bing";
        Thread.Sleep(TimeSpan.FromSeconds(3));
    });
  MessageBox.Show("done");
}

Якщо використовувати BeginInvoke , MessageBox з'являється одночасно з оновленням тексту. Якщо ви використовуєте Invoke , MessageBox спливає після сну 3 секунди. Отже, показ ефекту асинхронного ( BeginInvoke ) та синхронного ( Invoke ) виклику.


9

Delegate.BeginInvoke () асинхронно чергає виклик делегата і негайно повертає контроль. Використовуючи Delegate.BeginInvoke (), ви повинні зателефонувати Delegate.EndInvoke () у методі зворотного виклику, щоб отримати результати.

Delegate.Invoke () синхронно викликає делегата в одному потоці.

Стаття MSDN


8

Просто додайте, чому і коли використовувати Invoke ().

І Invoke (), і BeginInvoke () маршують код, який ви вказуєте в потоці диспетчера.

Але на відміну від BeginInvoke (), Invoke () зупиняє ваш потік, поки диспетчер не виконає ваш код. Ви можете використовувати Invoke (), якщо вам потрібно призупинити асинхронну операцію, поки користувач не надішле якийсь зворотній зв'язок.

Наприклад, ви можете зателефонувати Invoke (), щоб запустити фрагмент коду, який відображає діалогове вікно OK / Скасувати. Після того, як користувач натисне на кнопку і ваш маршований код завершиться, метод invoke () повернеться, і ви можете діяти за відповіддю користувача.

Дивіться Pro WPF в C # главі 31

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.