线程实用解析---------(四)异步操作
2012-10-05 19:33
363 查看
在实际的编程中某些任务执行完成时间可能较长,比如打开大文件、连接远程计算机或查询数据库,这个时候如果采用异步操作可以极大提高程序的运行效率,提供良好用户体验。异步操作在主应用程序线程以外的线程中执行。应用程序调用方法异步执行某个操作时,应用程序仍然可以继续执行当前的程序。
下面列举了.NET Framework 中支持异步编程的部分,主要包括: 文件(File) IO、流(Stream) IO、套接字(Socket) IO,网络,远程处理信道(HTTP、TCP)和代理,使用 ASP.NET 创建的 XML Web services,ASP.NET Web 窗体,使用 MessageQueue 类的消息队列等。
谈到异步操作,就不得不说异步委托,可以说异步委托在实现异步操作方面可谓有得天独厚的优势。那么什么是异步委托呢?异步委托就是定义一个方法,开一个新线程,让这个方法在后台执行。委托是方法的类型安全引用。Delegate类支持异步调用的方法,在后台Delegate类会创建一个执行任务的线程。
在.NET平台下,主要通过委托的BeginInvoke()来实现异步操作。
下面我会先通过一个小例子给大家进行解析。
首先创建一个委托
Public delegate void SayHello(string name);
然后在程序的主函数里写下如下代码:
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主线程ID
SayHello sayhello = new SayHello(Say);//新建一个委托对象
sayhello.BeginInvoke("Olive", null, null);//调用委托的异步函数BeginInvoke(),这里边三个参数,第一个参数,为所调用的函数传递的参数,第二、第三个会在下边慢慢介绍
private static void Say(string name)
{
Console.WriteLine("Hello!--------" + name);
Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId);//显示当前函数执行时所在线程
}
实验结果如下:
通过这个简单的小例子我们可以发现:通过委托所实现的异步,不过是又启用了一个新的线程,但是大家要注意的是这个线程是线程池里的线程,是属于后台线程的。
下面我们继续,刚刚我们做的例子是不需要返回结果的异步操作,而实际的开发中,往往需要有返回的结果。那该如何做呢?
首先我们还是要先建一个委托:
delegate string SayHello(string name);
在主函数中代码如下:
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主线程ID
SayHello sayhello = new SayHello(Say);
IAsyncResult iResult=sayhello.BeginInvoke("Olive", null, null);//Delegate.BeginInvoke()方法实际上是一个IAsyncResult的对象
string result = sayhello.EndInvoke(iResult);//Delegate.EndInvoke()方法就是返回调用函数的返回值,但是该方法需要一个IAsyncResult对象,也就是委托调用BeginInvoke()开始异步
Console.WriteLine(result);
Console.ReadKey();
}
private static string Say(string name)
{
Console.WriteLine("Hello!--------" + name);
Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId);
return "I Love you " + name;
}
实验结果如下:
但是这个时候又有一个问题出现了,刚刚我们所举的异步操作只是很简单的返回一句话而已,如果是非常耗时的异步操作的话,我们也不知道操作有没有结束,如果在未结束时调用Delegate.EndInvoke()会一直的处在阻塞状态。这个时候该怎么办呢?
可以有三种办法解决这个问题:
第一个就是反复的询问
只需要在主函数里做如下修改即可:
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主线程ID
SayHello sayhello = new SayHello(Say);
IAsyncResult iResult=sayhello.BeginInvoke("Olive", null, null);//Delegate.BeginInvoke()方法实际上是一个IAsyncResult的对象
If(iResult.IsCompleted)
{
string result = sayhello.EndInvoke(iResult);//Delegate.EndInvoke()方法就是返回调用函数的返回值,但是该方法需要一个IAsyncResult对象,也就是委托调用BeginInvoke()开始异步
Console.WriteLine(result);
}
Console.ReadKey();
}
第二个方法:使用IAsyncReault相关联的等待句柄,使用AsyncWaitHandle属性就可以访问等待句柄。这个属性返回WaitHandle类型的对象,它可以等待委托线程完成其任务。WaitOne()方法将一个超时时间作为可选的第一个参数,在其中可以定义要等待的最长时间。如果发生超时WaitOne方法就返回false
if (iResult.AsyncWaitHandle.WaitOne(1000,false)) //如果等待超过1秒,则无法返回结果
{
string result = sayhello.EndInvoke(iResult);
Console.WriteLine(result);
}
第三种方法:异步回调。这个方法是最为推荐的方法。
那么什么是异步回调呢?或许刚刚大家有注意到在调用Delegate.BeginInvoek()方法时,只有有三个参数BeginInvoke(object parameter,AsyncCallback asynccallback,object state),上面只讲第一个参数,也就是委托调用的有参函数所需的参数,多个参数也可以,只需要按照委托声明时的顺序依次添加就可以了,第二个是一个AsyncCallBack类型的委托也就是异步操作执行完后要执行的委托函数,比如需要返回结果、输出什么的都可以在这个委托函数里执行,该委托函数必须有一个IAsyncResult类型的参数。第三个是额外的状态参数,一般都是该委托对象。
下面通过实例给大家进行讲解。
第一步还是先建立一个委托
delegate string SayHello(string name);
主函数:
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主 线程ID
SayHello sayhello = new SayHello(Say);
IAsyncResult iResult=sayhello.BeginInvoke("Olive",new AsyncCallback(Result), sayhello);//三个参数:1、Say()函数的参数,2、AsyncCallback类型的委托,(异步操作结束后执行的委托函数),3、将sayhello对象作为状态参数,在Result函数中会有用到该参数
Console.ReadKey();
}
//AsyncCallback委托所执行的函数
private static void Result(IAsyncResult iasyncresult)
{
SayHello sayhello = (SayHello)iasyncresult.AsyncState;//获取IAsyncResult对象的AsyncState的属性,即为Delegate.BeginInvoke()的第三个参数即sayhello。
string s = sayhello.EndInvoke(iasyncresult);
Console.WriteLine(s + "------好了,异步调用到这里已经结束了");
}
private static string Say(string name)
{
Console.WriteLine("Hello!--------" + name);
Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId);
return "I Love you " + name;
}
实验结果如图:
至此,本节的异步操作已经结束了,在实际的运用中异步操作用的还是比较多的,建议大家在使用异步操作的时候多用下异步回调,这种方法效率比较高、也不会发生异步的阻塞。
下面列举了.NET Framework 中支持异步编程的部分,主要包括: 文件(File) IO、流(Stream) IO、套接字(Socket) IO,网络,远程处理信道(HTTP、TCP)和代理,使用 ASP.NET 创建的 XML Web services,ASP.NET Web 窗体,使用 MessageQueue 类的消息队列等。
谈到异步操作,就不得不说异步委托,可以说异步委托在实现异步操作方面可谓有得天独厚的优势。那么什么是异步委托呢?异步委托就是定义一个方法,开一个新线程,让这个方法在后台执行。委托是方法的类型安全引用。Delegate类支持异步调用的方法,在后台Delegate类会创建一个执行任务的线程。
在.NET平台下,主要通过委托的BeginInvoke()来实现异步操作。
下面我会先通过一个小例子给大家进行解析。
首先创建一个委托
Public delegate void SayHello(string name);
然后在程序的主函数里写下如下代码:
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主线程ID
SayHello sayhello = new SayHello(Say);//新建一个委托对象
sayhello.BeginInvoke("Olive", null, null);//调用委托的异步函数BeginInvoke(),这里边三个参数,第一个参数,为所调用的函数传递的参数,第二、第三个会在下边慢慢介绍
private static void Say(string name)
{
Console.WriteLine("Hello!--------" + name);
Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId);//显示当前函数执行时所在线程
}
实验结果如下:
通过这个简单的小例子我们可以发现:通过委托所实现的异步,不过是又启用了一个新的线程,但是大家要注意的是这个线程是线程池里的线程,是属于后台线程的。
下面我们继续,刚刚我们做的例子是不需要返回结果的异步操作,而实际的开发中,往往需要有返回的结果。那该如何做呢?
首先我们还是要先建一个委托:
delegate string SayHello(string name);
在主函数中代码如下:
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主线程ID
SayHello sayhello = new SayHello(Say);
IAsyncResult iResult=sayhello.BeginInvoke("Olive", null, null);//Delegate.BeginInvoke()方法实际上是一个IAsyncResult的对象
string result = sayhello.EndInvoke(iResult);//Delegate.EndInvoke()方法就是返回调用函数的返回值,但是该方法需要一个IAsyncResult对象,也就是委托调用BeginInvoke()开始异步
Console.WriteLine(result);
Console.ReadKey();
}
private static string Say(string name)
{
Console.WriteLine("Hello!--------" + name);
Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId);
return "I Love you " + name;
}
实验结果如下:
但是这个时候又有一个问题出现了,刚刚我们所举的异步操作只是很简单的返回一句话而已,如果是非常耗时的异步操作的话,我们也不知道操作有没有结束,如果在未结束时调用Delegate.EndInvoke()会一直的处在阻塞状态。这个时候该怎么办呢?
可以有三种办法解决这个问题:
第一个就是反复的询问
只需要在主函数里做如下修改即可:
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主线程ID
SayHello sayhello = new SayHello(Say);
IAsyncResult iResult=sayhello.BeginInvoke("Olive", null, null);//Delegate.BeginInvoke()方法实际上是一个IAsyncResult的对象
If(iResult.IsCompleted)
{
string result = sayhello.EndInvoke(iResult);//Delegate.EndInvoke()方法就是返回调用函数的返回值,但是该方法需要一个IAsyncResult对象,也就是委托调用BeginInvoke()开始异步
Console.WriteLine(result);
}
Console.ReadKey();
}
第二个方法:使用IAsyncReault相关联的等待句柄,使用AsyncWaitHandle属性就可以访问等待句柄。这个属性返回WaitHandle类型的对象,它可以等待委托线程完成其任务。WaitOne()方法将一个超时时间作为可选的第一个参数,在其中可以定义要等待的最长时间。如果发生超时WaitOne方法就返回false
if (iResult.AsyncWaitHandle.WaitOne(1000,false)) //如果等待超过1秒,则无法返回结果
{
string result = sayhello.EndInvoke(iResult);
Console.WriteLine(result);
}
第三种方法:异步回调。这个方法是最为推荐的方法。
那么什么是异步回调呢?或许刚刚大家有注意到在调用Delegate.BeginInvoek()方法时,只有有三个参数BeginInvoke(object parameter,AsyncCallback asynccallback,object state),上面只讲第一个参数,也就是委托调用的有参函数所需的参数,多个参数也可以,只需要按照委托声明时的顺序依次添加就可以了,第二个是一个AsyncCallBack类型的委托也就是异步操作执行完后要执行的委托函数,比如需要返回结果、输出什么的都可以在这个委托函数里执行,该委托函数必须有一个IAsyncResult类型的参数。第三个是额外的状态参数,一般都是该委托对象。
下面通过实例给大家进行讲解。
第一步还是先建立一个委托
delegate string SayHello(string name);
主函数:
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主 线程ID
SayHello sayhello = new SayHello(Say);
IAsyncResult iResult=sayhello.BeginInvoke("Olive",new AsyncCallback(Result), sayhello);//三个参数:1、Say()函数的参数,2、AsyncCallback类型的委托,(异步操作结束后执行的委托函数),3、将sayhello对象作为状态参数,在Result函数中会有用到该参数
Console.ReadKey();
}
//AsyncCallback委托所执行的函数
private static void Result(IAsyncResult iasyncresult)
{
SayHello sayhello = (SayHello)iasyncresult.AsyncState;//获取IAsyncResult对象的AsyncState的属性,即为Delegate.BeginInvoke()的第三个参数即sayhello。
string s = sayhello.EndInvoke(iasyncresult);
Console.WriteLine(s + "------好了,异步调用到这里已经结束了");
}
private static string Say(string name)
{
Console.WriteLine("Hello!--------" + name);
Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId);
return "I Love you " + name;
}
实验结果如图:
至此,本节的异步操作已经结束了,在实际的运用中异步操作用的还是比较多的,建议大家在使用异步操作的时候多用下异步回调,这种方法效率比较高、也不会发生异步的阻塞。
相关文章推荐
- 线程实用详解--------(四)异步操作
- 异步与线程深度解析
- Android中使用Handler和异步任务(AsyncTack)来为UI线程执行费时操作
- ios的线程和同步异步操作
- 线程实用解析---------(一)线程初识
- Java8 Lambda表达应用 -- 单线程游戏server+异步数据库操作
- 用委托在listbox中异步显示信息,解决线程间操作无效,从不是创建控件的线程访问它
- 【Android高级部分】线程和异步操作-AsyncTask使用
- C# 线程知识--使用Task执行异步操作
- 线程实用解析---------(二)创建调用有参函数的线程和线程池简介
- Android:在子线程中更新UI,解析异步消息处理机制(Handler)
- C# 线程知识--使用ThreadPool执行异步操作
- C# 线程知识--使用Task执行异步操作
- C# 线程知识--使用Task执行异步操作
- android 异步线程刷新UI 以及 JSON解析 以及 url get请求
- 【OSC手机App技术解析】- 列表异步线程加载图片
- CLR_via_C#.3rd 翻译[25.7 使用专用线程执行异步的计算限制操作]
- 【C#】C#线程_计算限制的异步操作
- 线程实用解析--------(五)BackgroundWorker和Timer
- Linux C编程--线程操作线程属性解析