zoukankan      html  css  js  c++  java
  • C#中Invoke 和 BeginInvoke 的区别

    C#中Invoke 和 BeginInvoke 的区别

    相关资料:Invoke 和 BeginInvoke 的真正涵义 、在多线程中如何调用Winform

    Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托。

    Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托。

    Control的Invoke和BeginInvoke 是相对于支线线程(因为一般在支线线程中调用,用来更新主线程ui)Invoke立即插入主线程中执行,而BeginInvoke 要等主线程结束才执行

    (一)、Control的Invoke和BeginInvoke
            我们要基于以下认识:
    (1)Control的Invoke和BeginInvoke与Delegate的Invoke和BeginInvoke是不同的。
    (2)Control的Invoke和BeginInvoke的参数为delegate,委托的方法是在Control的线程上执行的,也就是我们平时所说的UI线程。

    /*Control的Invoke*/
    private delegate void InvokeDelegate();
    private void InvokeMethod(){
       //C代码段
    }
    private void butInvoke_Click(object sender, EventArgs e) {
       //A代码段.......
       this.Invoke(new InvokeDelegate(InvokeMethod));
       //B代码段......
    }

    你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上
    A---------------->C---------------->B
    解释:

    (1)A在UI线程上执行完后,开始Invoke,Invoke是同步
    (2)代码段B并不执行,而是立即在UI线程上执行InvokeMethod方法,即代码段C。
    (3)InvokeMethod方法执行完后,代码段B才在UI线程上继续执行。

    [ 代码Ⅱ]    Control的BeginInvoke

    /*Control的BeginInvoke*/
    private delegate void BeginInvokeDelegate();
    private void BeginInvokeMethod()
    {
       //C代码段
    }
    private void butBeginInvoke_Click(object sender, EventArgs e) 
    {
       //A代码段.......
       this.BeginInvoke(new BeginInvokeDelegate(BeginInvokeMethod));
       //B代码段......
    }

    你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上
    A---------------->B---------------->C慎重,这个只做参考。。。。。,我也不肯定执行顺序,如果有哪位达人知道的话请告知。
    解释:

    (1)A在UI线程上执行完后,开始BeginInvoke,BeginInvoke是异步

    由此,我们知道:
    Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行的。也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面什么的,千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死。

    那么,这个异步到底是什么意思呢?

    异步是指相对于调用BeginInvoke的线程异步,而不是相对于UI线程异步,你在UI线程上调用BeginInvoke ,当然不行了。----摘自"Invoke和BeginInvoke的真正涵义"一文中的评论。
    BeginInvoke的原理是将调用的方法Marshal成消息,然后调用Win32 API中的RegisterWindowMessage()向UI窗口发送消息。----摘自"Invoke和BeginInvoke的真正涵义"一文中的评论。

    (二)、我们用Thread来调用BeginInvoke和Invoke
          我们开一个线程,让线程执行一些耗费时间的操作,然后再用Control.Invoke和Control.BeginInvoke回到用户UI线程,执行界面更新。
     

    [ 代码Ⅲ ]    Thread调用Control的Invoke

    /*Thread调用Control的Invoke*/
    private Thread invokeThread;
    private delegate void invokeDelegate();
    private void StartMethod()
    {
       //C代码段......
       Control.Invoke(new invokeDelegate(invokeMethod));
       //D代码段......
    }
    private void invokeMethod()
    {
      //E代码段
    }
    private void butInvoke_Click(object sender, EventArgs e) 
    {
       //A代码段.......
       invokeThread = new Thread(new ThreadStart(StartMethod));
       invokeThread.Start();
       //B代码段......
    }

    你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上
    A------>(Start一开始B和StartMethod的C就同时执行)---->(C执行完了,不管B有没有执行完,invokeThread把消息封送(invoke)给UI线程,然后自己等待)---->UI线程处理完butInvoke_Click消息后,处理invokeThread封送过来的消息,执行invokeMethod方法,即代码段E,处理往后UI线程切换到invokeThread线程。
    这个Control.Invoke是相对于invokeThread线程同步的,阻止了其运行。

    解释:
    1。UI执行A
    2。UI开线程InvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程invokeThread上。
    3。invokeThread封送消息给UI,然后自己等待,UI处理完消息后,处理invokeThread封送的消息,即代码段E
    4。UI执行完E后,转到线程invokeThread上,invokeThread线程执行代码段D

    [ 代码Ⅳ ]    Thread调用Control的BeginInvoke

    /*Thread调用Control的BeginInvoke*/
    private Thread beginInvokeThread;
    private delegate void beginInvokeDelegate();
    private void StartMethod()
    {
       //C代码段......
       Control.BeginInvoke(new beginInvokeDelegate(beginInvokeMethod));
       //D代码段......
    }
    private void beginInvokeMethod()
    {
      //E代码段
    }
    private void butBeginInvoke_Click(object sender, EventArgs e) 
    {
       //A代码段.......
       beginInvokeThread = new Thread(new ThreadStart(StartMethod));
       beginInvokeThread .Start();
       //B代码段......
    }

    你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上
    A在UI线程上执行----->beginInvokeThread线程开始执行,UI继续执行代码段B,并发地invokeThread执行代码段C-------------->不管UI有没有执行完代码段B,这时beginInvokeThread线程把消息封送给UI,单自己并不等待,继续向下执行-------->UI处理完butBeginInvoke_Click消息后,处理beginInvokeThread线程封送过来的消息。

    解释:

    (三)、总结

    Control的BeginInvoke是相对于调用它的线程,即beginInvokeThread相对是异步的。
    因此,我们可以想到。如果要异步取耗费长时间的数据,比如从数据库中读大量数据,我们应该这么做。
    (1)如果你想阻止调用线程,那么调用[ 代码Ⅲ ],代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
    (2)如果你不想阻止调用线程,那么调用[ 代码Ⅳ ],代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。

    What's the difference between Invoke() and BeginInvoke()

    Asked 11 years, 2 months ago

    Just wondering what the difference between BeginInvoke() and Invoke() are?

    Mainly what each one would be used for.

    EDIT: What is the difference between creating a threading object and calling invoke on that and just calling BeginInvoke() on a delegate? or are they the same thing?

    c# .net multithreading invoke begininvoke

    6 Answers

    Do you mean Delegate.Invoke/BeginInvoke or Control.Invoke/BeginInvoke?

    • Delegate.Invoke: Executes synchronously, on the same thread.
    • Delegate.BeginInvoke: Executes asynchronously, on a threadpool thread.
    • Control.Invoke: Executes on the UI thread, but calling thread waits for completion before continuing.
    • Control.BeginInvoke: Executes on the UI thread, and calling thread doesn't wait for completion.

    Tim's answer mentions when you might want to use BeginInvoke - although it was mostly geared towards Delegate.BeginInvoke, I suspect.

    For Windows Forms apps, I would suggest that you should usually use BeginInvoke. That way you don't need to worry about deadlock, for example - but you need to understand that the UI may not have been updated by the time you next look at it! In particular, you shouldn't modify data which the UI thread might be about to use for display purposes. For example, if you have a Person with FirstName and LastName properties, and you did:

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

    then the UI may well end up displaying "Keyser Spacey". (There's an outside chance it could display "Kevin Soze" but only through the weirdness of the memory model.)

    Unless you have this sort of issue, however, Control.BeginInvoke is easier to get right, and will avoid your background thread from having to wait for no good reason. Note that the Windows Forms team has guaranteed that you can use Control.BeginInvoke in a "fire and forget" manner - i.e. without ever calling EndInvoke. This is not true of async calls in general: normally every BeginXXX should have a corresponding EndXXX call, usually in the callback.

    shareedit

    edited Dec 23 '09 at 21:34

    Matthew Groves

    20.8k88 gold badges5858 silver badges107107 bronze badges

    answered Oct 23 '08 at 12:40

    Jon Skeet

    1157k737737 gold badges83268326 silver badges86768676 bronze badges

    • 3

      Then why would ppl use Invoke over BeingInvoke? Shouldn't there be some advantages over using Invoke. Both executes processes in the background, just that one is on the same thread, the other on different thread? – yeeen Oct 8 '10 at 9:23

    • 2

      @Jon: While I am using Dispatcher.BeginInvoke my code is working fine and in Dispatcher.Invoke my application making me wait for few seconds then it initializes all controls then launching, Can you please help me to find out exactly in which place I stuck ? – SharpUrBrain May 4 '11 at 15:01

    • 1

      @SharpUrBrain: Well, what have you read, and which bits didn't you understand? – Jon Skeet May 4 '11 at 15:28

    • 5

      @SharpUrBrain: Control.BeginInvoke is sort of the equivalent of Dispatcher.BeginInvoke, but for WinForms (whereas Dispatcher is for WPF and Silverlight). – Jon Skeet May 4 '11 at 15:42

    • 3

      @SharpUrBrain: I would suggest you ask a specific question rather than continuing in comments - and of course check whether the same question has already been asked by someone else first. – Jon Skeet May 5 '11 at 6:26

    show 14 more comments

    44

    Building on Jon Skeet's reply, there are times when you want to invoke a delegate and wait for its execution to complete before the current thread continues. In those cases the Invoke call is what you want.

    In multi-threading applications, you may not want a thread to wait on a delegate to finish execution, especially if that delegate performs I/O (which could make the delegate and your thread block).

    In those cases the BeginInvoke would be useful. By calling it, you're telling the delegate to start but then your thread is free to do other things in parallel with the delegate.

    Using BeginInvoke increases the complexity of your code but there are times when the improved performance is worth the complexity.

    shareedit

    answered Oct 23 '08 at 12:49

    Tim Stewart

    4,34911 gold badge2323 silver badges3939 bronze badges

    add a comment

    24

    The difference between Control.Invoke() and Control.BeginInvoke() is,

    • BeginInvoke() will schedule the asynchronous action on the GUI thread. When the asynchronous action is scheduled, your code continues. Some time later (you don't know exactly when) your asynchronous action will be executed
    • Invoke() will execute your asynchronous action (on the GUI thread) and wait until your action has completed.

    A logical conclusion is that a delegate you pass to Invoke() can have out-parameters or a return-value, while a delegate you pass to BeginInvoke() cannot (you have to use EndInvoke to retrieve the results).

    shareedit

    answered Sep 11 '12 at 7:07

    Sujit

    3,12999 gold badges3434 silver badges5050 bronze badges

    add a comment

    18

    Just to give a short, working example to see an effect of their difference

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

    If use BeginInvoke, MessageBox pops simultaneous to the text update. If use Invoke, MessageBox pops after the 3 second sleep. Hence, showing the effect of an asynchronous (BeginInvoke) and a synchronous (Invoke) call.

    shareedit

    answered Dec 14 '12 at 5:11

    KMC

    17.1k4545 gold badges136136 silver badges228228 bronze badges

    add a comment

    8

    Delegate.BeginInvoke() asynchronously queues the call of a delegate and returns control immediately. When using Delegate.BeginInvoke(), you should call Delegate.EndInvoke() in the callback method to get the results.

    Delegate.Invoke() synchronously calls the delegate in the same thread.

    MSDN Article

    shareedit

    edited Oct 23 '08 at 13:11

    answered Oct 23 '08 at 12:47

    Aaron Palmer

    8,13188 gold badges4444 silver badges7575 bronze badges

    add a comment

    7

    Just adding why and when to use Invoke().

    Both Invoke() and BeginInvoke() marshal the code you specify to the dispatcher thread.

    But unlike BeginInvoke(), Invoke() stalls your thread until the dispatcher executes your code. You might want to use Invoke() if you need to pause an asynchronous operation until the user has supplied some sort of feedback.

    For example, you could call Invoke() to run a snippet of code that shows an OK/Cancel dialog box. After the user clicks a button and your marshaled code completes, the invoke() method will return, and you can act upon the user's response.

    See Pro WPF in C# chapter 31

  • 相关阅读:
    Asp.Net高级知识回顾_HttpModule及应用程序生命周期_1
    分析Http 请求
    Asp.Net基础知识回顾_状态管理
    泛型约束
    【转】TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端
    【转】【完全开源】微信客户端.NET版
    【转】【完全开源】百度地图Web service API C#.NET版,带地图显示控件、导航控件、POI查找控件
    【转】Android总结篇系列:Activity Intent Flags及Task相关属性
    【转】Android总结篇系列:Activity启动模式(lauchMode)
    【转】Android总结篇系列:Activity生命周期
  • 原文地址:https://www.cnblogs.com/grj001/p/12222977.html
Copyright © 2011-2022 走看看