ความแตกต่างระหว่าง Invoke () และ BeginInvoke () คืออะไร


398

แค่สงสัยว่าความแตกต่างระหว่างBeginInvoke()และInvoke()คืออะไร?

ส่วนใหญ่สิ่งที่แต่ละคนจะใช้สำหรับ

แก้ไข: อะไรคือความแตกต่างระหว่างการสร้างวัตถุเธรดและการเรียกใช้การเรียกนั้นและเพียงแค่เรียกBeginInvoke()ผู้แทน? หรือพวกเขาเป็นสิ่งเดียวกัน

คำตอบ:


568

คุณหมายถึงDelegate.Invoke/ BeginInvokeหรือControl.Invoke/ BeginInvoke?

  • Delegate.Invoke: ดำเนินการแบบซิงโครนัสบนเธรดเดียวกัน
  • Delegate.BeginInvoke: เรียกใช้แบบอะซิงโครนัสบนthreadpoolเธรด
  • Control.Invoke: ดำเนินการกับเธรด UI แต่การเรียกเธรดจะรอให้เสร็จสิ้นก่อนดำเนินการต่อ
  • Control.BeginInvoke: ดำเนินการกับเธรด UI และการเรียกเธรดไม่รอให้เสร็จสมบูรณ์

คำตอบของทิมกล่าวถึงเมื่อคุณอาจต้องการใช้BeginInvokeถึงแม้ว่ามันจะเหมาะสำหรับDelegate.BeginInvokeฉัน

สำหรับ Windows Forms แอพพลิเคผมจะแนะนำว่าคุณควรจะมักจะBeginInvokeใช้ ด้วยวิธีนี้คุณไม่ต้องกังวลเกี่ยวกับการหยุดชะงักตัวอย่างเช่น - แต่คุณต้องเข้าใจว่า UI อาจไม่ได้รับการอัปเดตเมื่อคุณดูครั้งต่อไป! โดยเฉพาะอย่างยิ่งคุณไม่ควรแก้ไขข้อมูลที่อาจใช้เธรด UI เพื่อจุดประสงค์ในการแสดงผล ตัวอย่างเช่นถ้าคุณมีPersonด้วยFirstNameและLastNameคุณสมบัติและคุณได้:

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

จากนั้น UI อาจจบลงด้วยการแสดง "Keyser Spacey" (มีโอกาสภายนอกที่สามารถแสดง "Kevin Soze" แต่ผ่านความแปลกประหลาดของโมเดลหน่วยความจำเท่านั้น)

อย่างไรก็ตามหากคุณไม่มีปัญหาประเภทนี้คุณสามารถทำให้Control.BeginInvokeถูกต้องได้ง่ายขึ้นและจะหลีกเลี่ยงเธรดพื้นหลังของคุณไม่ต้องรอโดยไม่มีเหตุผล หมายเหตุว่าทีมแบบฟอร์ม Windows ได้รับประกันได้ว่าคุณสามารถใช้Control.BeginInvokeใน "ไฟและลืม" ลักษณะ - EndInvokeคือโดยที่ไม่เคยเรียกร้อง สิ่งนี้ไม่เป็นความจริงของการโทรแบบ async โดยทั่วไป: ปกติแล้ว BeginXXX ทุกคนควรมีการเรียก EndXXX ที่สอดคล้องกันโดยปกติแล้วในการโทรกลับ


4
แล้วทำไม ppl ใช้ Invoke ผ่าน BeingInvoke? ไม่ควรมีข้อได้เปรียบมากกว่าการใช้ Invoke ทั้งสองดำเนินการกระบวนการในพื้นหลังเพียงหนึ่งที่อยู่ในหัวข้อเดียวกันอื่น ๆ ในหัวข้อที่แตกต่างกันอย่างไร
yeeen

2
@ จอน: ในขณะที่ฉันใช้ Dispatcher.BeginInvoke รหัสของฉันทำงานได้ดีและใน Dispatcher.Invoke แอปพลิเคชันของฉันทำให้ฉันรอไม่กี่วินาทีจากนั้นก็เริ่มต้นการควบคุมทั้งหมดแล้วเปิดตัวคุณช่วยกรุณาค้นหาว่าฉันติดอยู่ตรงไหน ?
SharpUrBrain

6
@SharpUrBrain: Control.BeginInvoke นั้นเทียบเท่ากับ Dispatcher.BeginInvoke แต่สำหรับ WinForms (ในขณะที่ Dispatcher สำหรับ WPF และ Silverlight)
Jon Skeet

4
@SharpUrBrain: ฉันขอแนะนำให้คุณถามคำถามเฉพาะแทนที่จะแสดงความคิดเห็นต่อไปและแน่นอนตรวจสอบว่าคำถามเดียวกันได้ถูกถามโดยคนอื่นก่อน
Jon Skeet

2
@AZ: ใช่โดย "บนเธรด UI" เขาหมายถึง "UI เธรด" ซึ่งเป็นเจ้าของหมายเลขอ้างอิงของตัวควบคุมนั้นโดยเฉพาะ โดยทั่วไปมีเพียงเธรด UI เดียว แต่เป็นไปได้ที่จะมีหลายเธรด UI และในแอปพลิเคชันขั้นสูงมีเหตุผลที่คุณต้องการ ในทางเทคนิคแล้วเธรดใด ๆ (ปกติ?) สามารถเริ่มการปั๊มข้อความ UI และกลายเป็นเธรด UI ได้และสามารถปิดปั๊มข้อความได้ในภายหลังและไม่เป็นเธรด UI อีกต่อไป (ฉันคิดว่านั่นไม่ใช่สิ่งที่ควรลองในเธรดพูลด้าย)
Rob Parker

46

จากคำตอบของ Jon Skeet มีหลายครั้งที่คุณต้องการเรียกผู้ร่วมประชุมและรอให้การดำเนินการเสร็จสิ้นก่อนที่เธรดปัจจุบันจะยังคงดำเนินต่อไป ในกรณีเหล่านั้นการเรียกใช้เรียกเป็นสิ่งที่คุณต้องการ

ในแอปพลิเคชันแบบมัลติเธรดคุณอาจไม่ต้องการให้เธรดรอให้ผู้รับมอบสิทธิ์ดำเนินการให้เสร็จสิ้นโดยเฉพาะหากผู้รับมอบสิทธิ์นั้นดำเนินการ I / O (ซึ่งอาจทำให้ผู้รับมอบสิทธิ์และบล็อกเธรดของคุณ)

ในกรณีเหล่านั้น 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 จะปรากฏขึ้นพร้อมกันกับการอัพเดตข้อความ ถ้าใช้การเรียกใช้MessageBox จะปรากฏหลังจากผ่านไป 3 วินาที ดังนั้นการแสดงผลของการโทรแบบอะซิงโครนัส ( BeginInvoke ) และการโทรแบบซิงโครนัส ( เรียกใช้ )


9

Delegate.BeginInvoke () แบบอะซิงโครนัสเข้าคิวการโทรของผู้รับมอบสิทธิ์และส่งคืนการควบคุมทันที เมื่อใช้ Delegate.BeginInvoke () คุณควรโทร Delegate.EndInvoke () ในวิธีการโทรกลับเพื่อรับผลลัพธ์

Delegate.Invoke () เรียกผู้ได้รับมอบหมายในชุดข้อความเดียวกัน

บทความ MSDN


8

เพียงเพิ่มสาเหตุและเวลาที่จะใช้ Invoke ()

ทั้ง Invoke () และ BeginInvoke () จะจัดการรหัสที่คุณระบุในเธรดโปรแกรมเลือกจ่ายงาน

แต่แตกต่างจาก BeginInvoke () Invoke () จะหยุดการทำงานเธรดของคุณจนกว่าโปรแกรมเลือกจ่ายงานจะเรียกใช้รหัสของคุณ คุณอาจต้องการใช้ Invoke () หากคุณต้องการหยุดการทำงานแบบอะซิงโครนัสชั่วคราวจนกว่าผู้ใช้จะได้รับข้อเสนอแนะบางอย่าง

ตัวอย่างเช่นคุณสามารถเรียกใช้ Invoke () เพื่อเรียกใช้โค้ดขนาดสั้นที่แสดงกล่องโต้ตอบตกลง / ยกเลิก หลังจากที่ผู้ใช้คลิกปุ่มและรหัส marshaled ของคุณเสร็จสมบูรณ์วิธีการเรียกใช้ () จะกลับมาและคุณสามารถดำเนินการตามการตอบสนองของผู้ใช้

ดู Pro WPF ใน C # ตอนที่ 31

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.