Jawaban:
Apakah maksud Anda Delegate.Invoke
/ BeginInvoke
atau Control.Invoke
/ BeginInvoke
?
Delegate.Invoke
: Menjalankan secara sinkron, pada utas yang sama.Delegate.BeginInvoke
: Menjalankan asynchronous, pada threadpool
utas.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 Person
with FirstName
dan LastName
properti, 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.BeginInvoke
lebih 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.BeginInvoke
cara "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.
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.
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 dieksekusiInvoke()
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).
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 ).
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.
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