Apa perbedaan antara Invoke () dan BeginInvoke ()

398

Hanya ingin tahu apa bedanya BeginInvoke()dan Invoke()apa?

Terutama untuk apa masing-masing digunakan.

EDIT: Apa perbedaan antara membuat objek threading dan memanggil memanggil itu dan hanya memanggil BeginInvoke()delegasi? atau mereka hal yang sama?

Nathan W
sumber

Jawaban:

568

Apakah maksud Anda Delegate.Invoke/ BeginInvokeatau Control.Invoke/ BeginInvoke?

  • Delegate.Invoke: Menjalankan secara sinkron, pada utas yang sama.
  • Delegate.BeginInvoke: Menjalankan asynchronous, pada threadpoolutas.
  • Control.Invoke: Menjalankan di utas UI, tetapi utas panggilan menunggu untuk selesai sebelum melanjutkan.
  • Control.BeginInvoke: Menjalankan di utas UI, dan utas panggilan tidak menunggu penyelesaian.

Jawaban Tim menyebutkan kapan Anda mungkin ingin menggunakan BeginInvoke- meskipun sebagian besar diarahkan Delegate.BeginInvoke, saya kira.

Untuk aplikasi Windows Forms, saya menyarankan agar Anda biasanya menggunakan BeginInvoke. Dengan begitu Anda tidak perlu khawatir tentang kebuntuan, misalnya - tetapi Anda perlu memahami bahwa UI mungkin belum diperbarui pada saat Anda melihatnya nanti! Secara khusus, Anda tidak boleh memodifikasi data yang mungkin akan digunakan utas UI untuk tujuan tampilan. Misalnya, jika Anda memiliki Personwith FirstNamedan LastNameproperti, dan Anda melakukannya:

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

Maka UI mungkin akhirnya menampilkan "Keyser Spacey". (Ada kemungkinan di luar itu bisa menampilkan "Kevin Soze" tetapi hanya melalui keanehan model memori.)

Namun, kecuali Anda memiliki masalah seperti ini, Control.BeginInvokelebih mudah untuk diperbaiki, dan akan menghindari utas latar belakang Anda karena harus menunggu tanpa alasan yang jelas. Perhatikan bahwa tim Windows Forms telah menjamin bahwa Anda dapat menggunakan Control.BeginInvokecara "api dan lupakan" - yaitu tanpa menelepon EndInvoke. Ini tidak berlaku untuk panggilan async secara umum: biasanya setiap BeginXXX harus memiliki panggilan EndXXX yang sesuai, biasanya dalam callback.

Jon Skeet
sumber
4
Lalu mengapa ppl menggunakan Invoke over BeingInvoke? Bukankah seharusnya ada beberapa kelebihan dibandingkan menggunakan Invoke. Keduanya menjalankan proses di latar belakang, hanya satu yang berada di utas yang sama, yang lain pada utas yang berbeda?
yeeen
2
@ Jon: Ketika saya menggunakan Dispatcher.BeginInvoke kode saya berfungsi dengan baik dan di Dispatcher.Invoke aplikasi saya membuat saya menunggu beberapa detik kemudian menginisialisasi semua kontrol kemudian meluncurkan, Bisakah Anda membantu saya mencari tahu di mana saya terjebak ?
SharpUrBrain
6
@ SharpUrBrain: Control.BeginInvoke adalah semacam setara dengan Dispatcher.BeginInvoke, tetapi untuk WinForms (sedangkan Dispatcher untuk WPF dan Silverlight).
Jon Skeet
4
@SharpUrBrain: Saya sarankan Anda mengajukan pertanyaan tertentu daripada melanjutkan komentar - dan tentu saja periksa apakah pertanyaan yang sama telah ditanyakan oleh orang lain terlebih dahulu.
Jon Skeet
2
@AZ: Ya, dengan "pada utas UI" yang ia maksud pada "utas UI" tertentu yang memiliki pegangan Kontrol khusus itu. Biasanya, hanya ada satu utas UI, tetapi dimungkinkan untuk memiliki beberapa utas UI, dan pada aplikasi lanjutan ada alasan mengapa Anda menginginkannya. Secara teknis, utas apa pun (normal?) Dapat memulai pompa pesan UI dan menjadi utas UI - dan kemudian dapat mematikan pompa pesan dan tidak lagi menjadi utas UI. (Saya menganggap itu bukan sesuatu untuk dicoba di utas threadpool.)
Rob Parker
46

Berdasarkan jawaban Jon Skeet, ada saatnya Anda ingin meminta delegasi dan menunggu eksekusi selesai sebelum utas saat ini berlanjut. Dalam kasus itu, panggilan Invoke adalah yang Anda inginkan.

Dalam aplikasi multi-threading, Anda mungkin tidak ingin utas menunggu delegasi untuk menyelesaikan eksekusi, terutama jika delegasi tersebut melakukan I / O (yang dapat membuat delegasi dan blokir utas Anda).

Dalam kasus tersebut, BeginInvoke akan bermanfaat. Dengan memanggilnya, Anda memberi tahu delegasi untuk memulai tetapi kemudian utas Anda bebas untuk melakukan hal-hal lain secara paralel dengan delegasi.

Menggunakan BeginInvoke meningkatkan kompleksitas kode Anda, tetapi ada kalanya peningkatan kinerja sebanding dengan kompleksitasnya.

Tim Stewart
sumber
27

Perbedaan antara Control.Invoke()dan Control.BeginInvoke()adalah,

  • BeginInvoke()akan menjadwalkan tindakan asinkron pada utas GUI. Ketika tindakan asinkron dijadwalkan, kode Anda berlanjut. Beberapa waktu kemudian (Anda tidak tahu persis kapan) tindakan asinkron Anda akan dieksekusi
  • Invoke() akan menjalankan tindakan asinkron Anda (pada utas GUI) dan menunggu hingga tindakan Anda selesai.

Kesimpulan logisnya adalah bahwa delegasi yang Anda lewati Invoke()dapat memiliki parameter atau nilai balik, sedangkan delegasi yang Anda lewati BeginInvoke()tidak bisa (Anda harus menggunakan EndInvoke untuk mengambil hasilnya).

Sujit
sumber
20

Sekedar memberi contoh, kerja singkat untuk melihat efek perbedaan mereka

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");
}

Jika menggunakan BeginInvoke , MessageBox muncul secara simultan ke pembaruan teks. Jika menggunakan Invoke , MessageBox muncul setelah 3 detik tidur. Oleh karena itu, menunjukkan efek panggilan asinkron ( BeginInvoke ) dan sinkron ( Invoke ).

KMC
sumber
9

Delegate.BeginInvoke () secara tidak sinkron mengantri panggilan delegasi dan segera mengembalikan kontrol. Saat menggunakan Delegate.BeginInvoke (), Anda harus memanggil Delegate.EndInvoke () dalam metode panggilan balik untuk mendapatkan hasilnya.

Delegate.Invoke () secara sinkron memanggil delegasi di utas yang sama.

Artikel MSDN

Aaron Palmer
sumber
8

Cukup tambahkan alasan dan waktu untuk menggunakan Invoke ().

Kedua Invoke () dan BeginInvoke () marshal kode yang Anda tentukan ke utas pengirim.

Tapi tidak seperti BeginInvoke (), Invoke () menghentikan utas Anda sampai operator mengeksekusi kode Anda. Anda mungkin ingin menggunakan Invoke () jika Anda perlu menjeda operasi asinkron sampai pengguna telah memberikan semacam umpan balik.

Misalnya, Anda bisa memanggil Invoke () untuk menjalankan cuplikan kode yang memperlihatkan kotak dialog OK / Batalkan. Setelah pengguna mengklik tombol dan kode marshal Anda selesai, metode invoke () akan kembali, dan Anda dapat bertindak atas respons pengguna.

Lihat Pro WPF dalam C # bab 31

Ingako
sumber