本文开始C#线程系列讲座之一,即如何使用BeginInvoke和EndInvoke。有需要的朋友可以参考一下。
语言:C#3.0
IDE:Visual Studio 2008
一、C#线程概述
在操作系统中,一个进程必须包含至少一个线程,然后,在某个时刻,需要同时执行同一个进程中的多个任务,或者为了提供者的性能,需要将要执行的任务拆分成多个子任务。这需要在同一个进程中打开多个线程。我们用C#写一个应用程序(控制台或者桌面),然后运行这个程序,打开windows任务管理器。此时,我们将看到该应用程序中包含的线程数,如下图所示。
如果任务管理器没有“线程数”列,您可以[查看][选择列]显示“线程数”列。从上图可以看出,几乎所有的进程都有两个以上的线程。可见,线程是提升应用程序性能的重要手段之一,尤其是在多核CPU机器上。
二、用委托(Delegate)的BeginInvoke和EndInvoke方法操作线程 c#中使用线程的方式有很多种。使用委托的BeginInvoke和EndInvoke方法就是其中之一。BeginInvoke方法可以使用线程异步执行委托指向的方法。然后通过EndInvoke方法获取方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值),或者确定方法已经被成功调用。我们可以通过四种方式从EndInvoke方法获得返回值。
第三,直接使用EndInvoke方法获取返回值。
当使用BeginInvoke异步调用方法时,如果方法没有完成,EndInvoke方法将一直阻塞,直到被调用的方法完成。如下面的代码所示:
复制代码如下:使用System使用系统。集合。泛型;使用系统。Linq使用系统。文本;使用系统。穿线;
命名空间my thread { class program { private static int new task(intms){ console . writeline(' task start ');线程。睡眠(毫秒);Random Random=new Random();int n=随机。下一个(10000);控制台。WriteLine(“任务已完成”);返回n;}
私有委托int new task delegate(int ms);
static void Main(string[]args){ new task delegate task=new task;IAsyncResult asyncResult=task。BeginInvoke(2000,null,null);
//EndInvoke方法将在result=task中被阻止2秒钟。endinvoke(async result);控制台。WriteLine(结果);} } }
运行上述程序后,由于newTask方法被Sleep延迟了2秒,程序直到2秒后才输出最终结果(一个随机整数)。如果不调用EndInvoke方法,程序会立即退出。这是因为用BeginInvoke创建的线程是后台线程。一旦所有前台线程退出(主线程是前台线程),这个线程将结束线程并退出程序,不管后台线程是否已经执行完。前台和后台线程的细节将在后面的部分解释。
读者可以用上面的程序做下面的实验。首先,在Main方法的开头添加以下代码:
复制代码如下:Thread。睡眠(10000);
在执行下面的代码之前,延迟Main方法10秒钟,然后按Ctrl+F5运行程序,打开企业管理器,观察当前程序中的线程数。假设线程数为4,10秒后,线程数将增加到5。这是因为调用BeginInvoke方法时,会建立一个线程来异步执行newTask方法,所以线程数会增加一个。
四、使用IAsyncResult asyncResult属性来判断异步调用是否完成
虽然上面的方法可以很好的实现异步调用,但是当调用EndInvoke方法得到调用结果时,整个程序就跟死了一样,不会让用户感觉太好。所以我们可以用asyncResult来判断异步调用是否完成,并显示一些提示信息。这样做可以增加用户体验。代码如下:
复制代码如下:static void main(string[]args){ newtaskdelegatetask=new task;IAsyncResult asyncResult=task。BeginInvoke(2000,null,null);
而(!异步结果。IsCompleted) {控制台。写(' * ');线程。睡眠(100);}//因为异步调用已经完成,EndInvoke会立即返回结果in result=task . end invoke(async result);控制台。WriteLine(结果);}以上代码的执行结果如下图所示。
因为是异步的,所以可能会在“任务开始”之前输出“*”,如上图所示。
五、使用WaitOne方法等待异步方法执行完成 使用WaitOne方法是判断异步调用是否完成的另一种方式。代码如下:
复制代码如下:static void main(string[]args){ newtaskdelegatetask=new task;IAsyncResult asyncResult=task。BeginInvoke(2000,null,null);
而(!异步结果。AsyncWaitHandle.WaitOne(100,false)) { Console。写(' * ');}
int结果=任务。EndInvoke(async result);控制台。WriteLine(结果);}
WaitOne的第一个参数指示等待的毫秒数。在指定的时间内,WaitOne方法将等待,直到异步调用完成并发出通知,WaitOne方法将返回true。等待指定时间后,异步调用仍未完成。WaitOne方法返回false。如果指定时间为0,则表示没有等待。如果为-1,则意味着永远等待,直到异步调用完成。
六、使用回调方式返回结果
以上方法其实只相当于一种方法。虽然这些方法可以成功返回结果,并给用户一些提示,但是在这个过程中,整个程序就像死了一样(如果读者在GUI程序中使用这些方法就会很明显)。如果程序在调用过程中还能正常做其他工作,就必须使用异步调用。让我们用GUI程序写一个例子。代码如下:
复制代码如下:私有委托int my method();private int方法(){ Thread。睡眠(10000);返回100;} private void method completed(IAsyncResult async result){ if(async result==null)返回;文本框1。Text=(asyncResult。AsyncState作为MyMethod)。EndInvoke(asyncResult)。ToString();}
私有void按钮1_Click(对象发送方,EventArgs e) {
MyMethod my=methodIAsyncResult asyncResult=my。BeginInvoke(MethodCompleted,my);}
注意,这里使用的是BeginInvoke方法的后两个参数(如果被调用的方法包含参数,这些参数将是BeginInvoke的第一部分参数;如果没有参数,BeginInvoke只有两个参数)。第一个参数是回调方法委托类型,它只有一个参数,即IAsyncResult,如MethodCompleted方法所示。当method方法完成后,系统会自动调用MethodCompleted方法。BeginInvoke的第二个参数需要传递一些值给MethodCompleted方法,一般可以传递被调用方法的委托,比如上面代码中的my。该值可以通过使用IAsyncResult获得。AsyncState属性。
由于上面的代码是以异步方式访问窗体上的一个textbox,所以需要按ctrl+f5才能运行程序(不能直接按F5运行程序,否则在其他线程中无法访问这个textbox。有关在其他线程中访问GUI组件的详细信息,请参考下一节)。并在窗体上放置一些其他可视控件。但是,点击button1后,其他控件仍然可以使用,就像什么都没发生一样。10秒钟后,textbox1中将输出100。
七。其他组件的BeginXXX和EndXXX方法
其他。net组件也有类似于BeginInvoke和EndInvoke的方法,比如系统的BeginGetResponse和EndGetResponse方法。HttpWebRequest类。下面是使用这两种方法的示例:
复制代码如下:private void请求完成(iasyncresult async result){ if(async result==null)返回;系统。net . http webrequest hwr=async result。AsyncState as系统。Net . HttpWebRequest系统。Net.HttpWebResponse响应=(系统。Net.HttpWebResponse)hwr。end getresponse(async result);系统。新系统。IO.StreamReader(响应。GetResponseStream());文本框1。text=Sr . ReadToEnd();}私人代表制度。net . http webresponse request delegate(System。Net.HttpWebRequest请求);
私有void按钮1_Click(对象发送方e) { System .网。HttpWebRequest请求=(系统. Net。HttpWebRequest)系统. net。网络请求。创建。jb51。net’);IAsyncResult asyncResult=请求BeginGetResponse(请求完成,请求);}
以上介绍的就是C#线程中贝京尼克和EndInvoke方法。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。