2009-12-15 26 views
16

Lời chào, Tôi đang phát triển một số ứng dụng trong C#. Tại thời điểm này tôi đang đối phó với luồng và tôi có một câu hỏi mà tôi có trong tâm trí của tôi. Sự khác nhau giữa Invoke và BeginInvoke là gì? Tôi đọc một số chủ đề và tôi tìm thấy một số thông tin hữu ích ở đây: hereGọi và BeginInvoke

Tuy nhiên sự khác biệt giữa Invoke và BeginInvoke trong đoạn mã sau là gì:

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

nơi MyDelegate là một tham chiếu đến chức năng MessageHandler.

Tôi nhận thấy rằng việc sử dụng BeginInvoke lblStatus.Text không được làm mới khi sử dụng Invoke làm mới nhãn. Ngoài ra tôi biết rằng Invoke chờ đợi để thực hiện của nó để hoàn thành. Trường hợp quan trọng nhất mà tôi quan tâm là tại sao có sự khác biệt trong văn bản nhãn làm mới trong trường hợp này.

Trả lời

8

Với Gọi phương thức được thực hiện và ứng dụng đợi cho đến khi hoàn thành.

Với BeginInvoke, phương thức được gọi Asychnronously và ứng dụng tiếp tục thực thi trong khi phương thức được tham chiếu trong BeginInvoke được thực thi.

Với BeginInvoke bạn cần gọi EndInvoke để nhận kết quả của phương thức bạn đã thực hiện bằng BeginIvnoke.

Bạn không nên cập nhật các thành phần GUI trong các phương thức BeginXXX khi chúng được chạy trong một luồng khác với luồng GUI, trái với phương thức Gọi của bạn. Bạn không thể truy cập các thành phần GUI trong một luồng khác với luồng GUI.

Hy vọng điều này sẽ hữu ích!

+12

Calling BeginInvoke không có nghĩa là nó không thực hiện trên giao diện người dùng chủ đề. Nó có nghĩa là nó được gọi là không đồng bộ trên chuỗi liên kết với "this" có thể là chuỗi giao diện người dùng. –

+0

vì vậy nếu nó không phải trong một chủ đề khác, làm thế nào nó hoạt động sau đó? –

+8

Từ MSDN: "Thực thi đại biểu được chỉ định không đồng bộ trên chuỗi mà điều khiển bên dưới của điều khiển được tạo trên". Vì vậy, nếu nó được gọi là từ các chủ đề giao diện người dùng, nó sẽ được đặt trên một hàng đợi và thực hiện khi các chủ đề giao diện người dùng nó nhàn rỗi. Mà sẽ được sau khi phương pháp hiện đang thực hiện đã trở lại. –

1

BeginInvoke thực thi thân phương thức trên một chuỗi khác và cho phép chuỗi hiện tại tiếp tục. Nếu bạn đang cố gắng cập nhật trực tiếp một thuộc tính điều khiển từ một luồng khác, nó sẽ ném một ngoại lệ.

+1

vâng tôi biết rằng, nhưng tại sao sử dụng Gọi văn bản nhãn của tôi được làm mới và sử dụng BeginInvoke nó không phải là –

+0

@Niao thấy câu thứ hai của câu trả lời của tôi –

0

Điều này về cơ bản là bạn có muốn điều khiển được cập nhật đồng bộ hoặc không đồng bộ hay không. Tất cả điều này phụ thuộc vào tình hình cụ thể của bạn.

18

Để bắt đầu, từ liên kết của bạn:

  • Control.Invoke: Thực thi trên thread UI, nhưng kêu gọi chủ đề chờ đợi để hoàn thành trước khi tiếp tục.
  • Control.BeginInvoke: Thực thi trên chuỗi giao diện người dùng không đồng bộ và chuỗi cuộc gọi không chờ hoàn thành.

và từ MSDN:

BeginInvoke thực hiện các đại biểu quy định không đồng bộ trên thread xử lý cơ bản của kiểm soát được tạo ra về.

Để tổng hợp, BeginInvokekhông đồng bộ. Khi BeginInvoke được gọi từ chuỗi giao diện người dùng, yêu cầu sẽ được thực thi song song với chuỗi giao diện người dùng. Điều đó có nghĩa là nó có thể không thực thi cho đến sau khi phương thức thực hiện hiện tại đã trả về.Vì vậy, trong trường hợp này, hộp văn bản sẽ không bao giờ xuất hiện để cập nhật vì vòng lặp for sẽ không bị gián đoạn, vì chuỗi cuộc gọi sẽ không chờ sự kiện này được hoàn thành trước khi tiếp tục.

Hoặc, Invokeđồng bộ. Hộp văn bản sẽ được cập nhật vì chuỗi cuộc gọi sẽ chờ cuộc gọi hoàn tất trước khi tiếp tục thực hiện.

+2

Một điểm nhỏ - nó không được thực thi khi phương thức trả về, nó được thực hiện như một đám cháy và quên - nó bị sa thải vào ether COM/winapi –

+0

Cảm ơn phản hồi của bạn; Tôi vừa cập nhật câu trả lời của mình. –

5

Control.BeginInvoke không hoạt động trên một luồng khác (hoặc threadpool), một delegate.BeginInvoke sẽ làm. MSDN của một liner nói:

Thực thi các đại biểu nhất định không đồng bộ trên thread xử lý cơ bản các kiểm soát là tạo ra về.

Tuy nhiên Control.BeginInvoke chỉ cần sử dụng PostMessage và trả về - không CLR Thread được tạo.

Chức năng PostMessage đặt (bài viết) một thông điệp trong hàng đợi thông điệp liên quan đến các chủ đề mà tạo ra cửa sổ chỉ định và lợi nhuận mà không cần chờ cho thread để xử lý tin nhắn.

This article tóm tắt xem có sử dụng Invoke hoặc BeginInvoke khá tốt:

Những chức năng để sử dụng, bạn yêu cầu. Nó thực sự phụ thuộc vào yêu cầu của bạn. Nếu bạn muốn cập nhật giao diện người dùng của mình hoàn thành trước khi tiếp tục, bạn sử dụng Gọi. Nếu không có yêu cầu như vậy, tôi muốn đề xuất sử dụng BeginInvoke, vì nó làm cho chuỗi gọi dường như là "nhanh hơn". Tuy nhiên, có một vài số của gotcha là với BeginInvoke.

  • Nếu chức năng bạn đang gọi qua BeginInvoke các truy cập chia sẻ trạng thái (trạng thái chia sẻ giữa các thread UI và chủ đề khác), bạn đang ở trong rắc rối. Tiểu bang có thể thay đổi giữa thời gian bạn gọi là BeginInvoke và khi chức năng được gói thực sự thực thi, dẫn đến việc gặp khó khăn trong việc tìm các vấn đề về thời gian .
  • Nếu bạn đang chuyển tham số tham chiếu đến hàm được gọi là qua BeginInvoke, thì bạn phải đảm bảo mà không ai khác sửa đổi đối tượng được chuyển trước khi hàm hoàn tất. Thông thường, mọi người nhân bản đối tượng trước khi chuyển nó đến BeginInvoke, để tránh sự cố hoàn toàn.
Các vấn đề liên quan