C# 异步编程Invoke、beginInvoke、endInvoke的用法和作用
一、Invoke
Invoke的本质只是一个方法,方法一定是要通过对象来调用的。
一般来说,Invoke其实用法只有两种情况:
Control的Invoke
Delegate的Invoke
也就是说,Invoke前面要么是一个控件,要么是一个委托对象。
Control的Invoke
Control的Invoke一般用于解决跨线程访问的问题,比如你想操作一个按钮button,你就要用button.Invoke,你想操作一个文本label,你就要用label.Invoke,但是大家会发现很麻烦,如果我想既操作button,又操作label,能不能写在一起呢?当然可以。
我们知道,主窗体是一个Form,Form自然也是继承Control的,所以Form也有Invoke的方法,可以直接调用Form.Invoke,这就是我们常见的this.Invoke。这就是为什么有的Invoke前面啥都没有的问题,其实前面是this,只不过省略了。
示例:
this.Invoke(new Action(() =>{ button1.Text = "关闭";}));
Delegate的Invoke
Delegate的Invoke其实就是从线程池中调用委托方法执行,Invoke是同步的方式,会卡住调用它的UI线程。
void PrintMessage(string message)
{
Console.WriteLine(message);
}
MyDelegate myDelegate = PrintMessage;
myDelegate.Invoke("Hello, World!"); // 使用 Invoke 方法调用委托引用的方法`
beginInvoke、endInvoke
我们已经知道 C#当中 存在async/await 、BackGroudWorker类以及TPL(任务并行库)。当然C#还有一些旧的模式来支持异步编程。
delegate long MyDel(int first, int second);
class Program
{
static long Sum(int x, int y)
{
Console.WriteLine("------Inside Sum@{0}", DateTime.Now.ToString());
Thread.Sleep(2000);
return x + y;
}
static void Main(string[] args)
{
MyDel del = new MyDel(Sum);
Console.WriteLine("Before BeginInvoke---@{0}", DateTime.Now.ToString());
IAsyncResult iar = del.BeginInvoke(3, 5, null, null);
Console.WriteLine("After BeginInvoke@{0}", DateTime.Now.ToString());
Console.WriteLine("Doing stuff@{0}", DateTime.Now.ToString());
long result = del.EndInvoke(iar);
Console.WriteLine("End Invoke@{0}", DateTime.Now.ToString());
Console.WriteLine("After EndInvoke: {0}", result);
Console.ReadKey();
}
}
如上代码,定义了一个委托 MyDel ,并且在调用的时候把Sum方法传给了它的对象。一般情况下我们调用这个委托对象,它就会调用他调用列表中包含的方法。就想调用方法一样,这是同步完成的。
但是如果委托对象在调用列表中只有一个方法(引用方法),它就可以异步的去执行这个方法。BeginInovke和EndInvoke就是用来做这个事的。我们可以用如下的方式使用:
* ①当我们调用BeginInvoke方法的时候,他开始在一个独立的线程上执行引用方法,并且立即返回到原始线程。原始线程可以继续,而引用方法会在想吃的线程中并行执行。
* ②当程序希望获取已完成的异步方法的结果时,可以检查BeginInvoke返回的IAsyncResult的IsCompleted属性,或者调用委托的EndInvoke方法来等待委托执行完成。
上面的使用过程就引出的三种模式:
* ①等待-直到完成 原始线程在发起了异步方法以及做了一些其他处理之后,原始线程就中断并且等待异步方法执行完成之后再继续。
* ②轮询 ,原始线程定期检查发起的线程是否完成,如果没有则可以继续做其他的事情,
* ③回调 原始线程一直执行,无需等待或者检查发起的线程是否完成,发起的线程中的引用发放完成之后,发起的线程会调用回调方法,由回调方法在调用的EndInvoke之前处理异步方法的结果。
借鉴网站:
C#中Invoke和BeginInvoke实际应用详解_C#教程_脚本之家
C#线程委托BeginInvoke与EndInvoke的用法_C#教程_脚本之家