C#异步编程<转>

简介:
同步方法和异步方法的区别

同步方法调用在程序继续执行之前需要等待同步方法执行完毕返回结果
异步方法则在被调用之后立即返回以便程序在被调用方法完成其任务的同时执行其它操作

异步编程概览

.NET Framework 允许您异步调用任何方法。定义与您需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名

的 BeginInvoke 和 EndInvoke 方法。

BeginInvoke 方法用于启动异步调用。它与您需要异步执行的方法具有相同的参数,只不过还有两个额外的参数(将在稍后描述)。

BeginInvoke 立即返回,不等待异步调用完成。
BeginInvoke 返回 IasyncResult,可用于监视调用进度。

EndInvoke 方法用于检索异步调用结果。调用 BeginInvoke 后可随时调用 EndInvoke 方法;如果异步调用未完成,EndInvoke 将一直阻塞到

异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由

BeginInvoke 返回的 IAsyncResult。

四种使用 BeginInvoke 和 EndInvoke 进行异步调用的常用方法。调用了 BeginInvoke 后,可以:

1.进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。
2.使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后调用

EndInvoke。这里主要是主程序等待异步方法,等待异步方法的结果。
3.轮询由 BeginInvoke 返回的 IAsyncResult,IAsyncResult.IsCompeted确定异步调用何时完成,然后调用 EndInvoke。此处理个人认为与
相同。
4.将用于回调方法的委托传递给 BeginInvoke。该方法在异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。这是在强制装

换回调函数里面IAsyncResult.AsyncState(BeginInvoke方法的最后一个参数)成委托,然后用委托执行EndInvoke。
警告   始终在异步调用完成后调用 EndInvoke。

以上有不理解的稍后可以再理解。

 

例子

1)先来个简单的没有回调函数的异步方法例子

请再运行程序的时候,仔细看注释,对理解很有帮助。还有,若将注释的中的两个方法都同步,你会发现异步运行的速度优越性。

 

using  System;

 
namespace  ConsoleApplication1
 
{
     
class Class1
     
{
         
//声明委托
         public delegate void AsyncEventHandler();
 
         
//异步方法
         void Event1()
        
{
            Console.WriteLine(
"Event1 Start");
            System.Threading.Thread.Sleep(
4000);
            Console.WriteLine(
"Event1 End");
        }


        
// 同步方法
        void Event2()
        
{
            Console.WriteLine(
"Event2 Start");
            
int i=1;
            
while(i<1000)
            
{
                i
=i+1;
                Console.WriteLine(
"Event2 "+i.ToString());
            }

            Console.WriteLine(
"Event2 End");
        }


        [STAThread]
        
static void Main(string[] args)
        
{
            
long start=0;
            
long end=0;
            Class1 c 
= new Class1();
            Console.WriteLine(
"ready");
            start
=DateTime.Now.Ticks;

            
//实例委托
            AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
            
//异步调用开始,没有回调函数和AsyncState,都为null
            IAsyncResult ia = asy.BeginInvoke(nullnull);
            
//同步开始,
            c.Event2();
            
//异步结束,若没有结束,一直阻塞到调用完成,在此返回该函数的return,若有返回值。

           
            asy.EndInvoke(ia);

            
//都同步的情况。
            
//c.Event1();
            
//c.Event2();
           
            end 
=DateTime.Now.Ticks;
            Console.WriteLine(
"时间刻度差="+ Convert.ToString(end-start) );
            Console.ReadLine();
        }

    }

}



 

2)下面看有回调函数的WebRequest和WebResponse的异步操作。

using  System;
using  System.Net;
using  System.Threading;
using  System.Text;
using  System.IO;


//  RequestState 类用于通过
//  异步调用传递数据
public   class  RequestState
{
    
const int BUFFER_SIZE = 1024;
    
public StringBuilder RequestData;
    
public byte[] BufferRead;
    
public HttpWebRequest Request;
    
public Stream ResponseStream;
    
// 创建适当编码类型的解码器
    public Decoder StreamDecode = Encoding.UTF8.GetDecoder();

    
public RequestState()
    
{
        BufferRead 
= new byte[BUFFER_SIZE];
        RequestData 
= new StringBuilder("");
        Request 
= null;
        ResponseStream 
= null;
    }

}


//  ClientGetAsync 发出异步请求
class  ClientGetAsync
{
    
public static ManualResetEvent allDone = new ManualResetEvent(false);
    
const int BUFFER_SIZE = 1024;

    
public static void Main(string[] args)
    
{

        
if (args.Length < 1)
        
{
            showusage();
            
return;
        }


        
// 从命令行获取 URI
        Uri HttpSite = new Uri(args[0]);

        
// 创建请求对象
        HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(HttpSite);

        
// 创建状态对象
        RequestState rs = new RequestState();

        
// 将请求添加到状态,以便它可以被来回传递
        rs.Request = wreq;

        
// 发出异步请求
        IAsyncResult r = (IAsyncResult)wreq.BeginGetResponse(new AsyncCallback(RespCallback), rs);

        
// 将 ManualResetEvent 设置为 Wait,
        
// 以便在调用回调前,应用程序不退出
        allDone.WaitOne();
    }


    
public static void showusage()
    
{
        Console.WriteLine(
"尝试获取 (GET) 一个 URL");
        Console.WriteLine(
"\r\n用法::");
        Console.WriteLine(
"ClientGetAsync URL");
        Console.WriteLine(
"示例::");
        Console.WriteLine(
"ClientGetAsync http://www.microsoft.com/net/");
    }


    
private static void RespCallback(IAsyncResult ar)
    
{
        
// 从异步结果获取 RequestState 对象
        RequestState rs = (RequestState)ar.AsyncState;

        
// 从 RequestState 获取 HttpWebRequest
        HttpWebRequest req = rs.Request;

        
// 调用 EndGetResponse 生成 HttpWebResponse 对象
        
// 该对象来自上面发出的请求
        HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(ar);

        
// 既然我们拥有了响应,就该从
        
// 响应流开始读取数据了
        Stream ResponseStream = resp.GetResponseStream();

        
// 该读取操作也使用异步完成,所以我们
        
// 将要以 RequestState 存储流
        rs.ResponseStream = ResponseStream;

        
// 请注意,rs.BufferRead 被传入到 BeginRead。
        
// 这是数据将被读入的位置。
        IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);
    }



    
private static void ReadCallBack(IAsyncResult asyncResult)
    
{
        
// 从 asyncresult 获取 RequestState 对象
        RequestState rs = (RequestState)asyncResult.AsyncState;

        
// 取出在 RespCallback 中设置的 ResponseStream
        Stream responseStream = rs.ResponseStream;

        
// 此时 rs.BufferRead 中应该有一些数据。
        
// 读取操作将告诉我们那里是否有数据
        int read = responseStream.EndRead(asyncResult);

        
if (read > 0)
        
{
            
// 准备 Char 数组缓冲区,用于向 Unicode 转换
            Char[] charBuffer = new Char[BUFFER_SIZE];

            
// 将字节流转换为 Char 数组,然后转换为字符串
            
// len 显示多少字符被转换为 Unicode
            int len = rs.StreamDecode.GetChars(rs.BufferRead, 0, read, charBuffer, 0);
            String str 
= new String(charBuffer, 0, len);

            
// 将最近读取的数据追加到 RequestData stringbuilder 对象中,
            
// 该对象包含在 RequestState 中
            rs.RequestData.Append(str);


            
// 现在发出另一个异步调用,读取更多的数据
            
// 请注意,将不断调用此过程,直到
            
// responseStream.EndRead 返回 -1
            IAsyncResult ar = responseStream.BeginRead(rs.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);
        }

        
else
        
{
            
if (rs.RequestData.Length > 1)
            
{
                
// 所有数据都已被读取,因此将其显示到控制台
                string strContent;
                strContent 
= rs.RequestData.ToString();
                Console.WriteLine(strContent);
            }


            
// 关闭响应流
            responseStream.Close();

            
// 设置 ManualResetEvent,以便主线程可以退出
            allDone.Set();
        }

        
return;
    }

}


 

在这里有回调函数,且异步回调中又有异步操作。

首先是异步获得ResponseStream,然后异步读取数据。

这个程序非常经典。从中可以学到很多东西的。我们来共同探讨。

 

总结

上面说过,.net framework 可以异步调用任何方法。所以异步用处广泛。

在.net framework 类库中也有很多异步调用的方法。一般都是已Begin开头End结尾构成一对,异步委托方法,外加两个回调函数和AsyncState参数,组成异步操作的宏观体现。所以要做异步编程,不要忘了委托delegate、Begin,End,AsyncCallBack委托,AsyncState实例(在回调函数中通过IAsyncResult.AsyncState来强制转换),IAsycResult(监控异步),就足以理解异步真谛了。

原文地址:http://www.cnblogs.com/ericwen/archive/2008/03/12/1101801.html

 

 

本文转自温景良(Jason)博客园博客,原文链接:http://www.cnblogs.com/wenjl520/archive/2010/01/07/1641308.html,如需转载请自行联系原作者

相关文章
|
2月前
|
C# 开发者
深入理解C#中的`Task<T>`:异步编程的核心
【1月更文挑战第3天】本文旨在探讨C#中`Task<T>`的使用和理解,作为异步编程模式的核心组件。`Task<T>`允许开发者在不阻塞主线程的情况下执行异步操作,并返回一个指定类型`T`的结果。通过定义返回`Task<T>`的异步方法、使用`async`和`await`关键字、处理异常以及获取任务结果,开发者可以编写出高效且响应迅速的应用程序。此外,本文还介绍了如何配置任务以及实现任务的连续性和组合,为掌握C#中的异步编程提供了全面的指导。
|
11月前
|
C#
C#异步编程
C#异步编程
173 0
|
C#
c#异步编程
c#异步编程原理,await asnyc的使用方法。异步编程是指在程序执行过程中,不需要等待某个操作完成,就可以继续执行后续的代码。
281 0
|
C#
C#网络应用编程,实验七: 异步编程练习
C#网络应用编程,实验七: 异步编程练习
107 1
C#网络应用编程,实验七: 异步编程练习
|
C#
C#网络应用编程,异步编程基础练习
C#网络应用编程,异步编程基础练习
129 1
C#网络应用编程,异步编程基础练习
|
SQL 开发框架 .NET
C#5.0-原生异步编程方式
微软提供的最新的异步编程基础设施。它允许我们以模块化的方式设计程序,来组合不同的异步操作。
98 0
C#5.0-原生异步编程方式
|
Java .NET C#
C#并发编程之异步编程(线程讨论)
C#并发编程之异步编程(线程讨论)写在前面本篇是异步编程系列的第三篇,本来计划第三篇的内容是介绍异步编程中常用的几个方法,但是前两篇写出来后,身边的朋友总是会有其他问题,所以决定在续写一篇,作为异步编程(一)和异步编程(二)的补充。
1436 0
|
C# 编译器 数据库
C#并发编程之异步编程(二)
C#并发编程之异步编程(二)写在前面前面一篇文章介绍了异步编程的基本内容,同时也简要说明了async和await的一些用法。本篇文章将对async和await这两个关键字进行深入探讨,研究其中的运行机制,实现编码效率与运行效率的提升。
1400 0
C#并发编程之异步编程(一)
C#并发编程之异步编程(一) 写在前面       C#5.0中,对异步编程进行了一次革命性的重构,引入了async和await这两个关键字,使得开发人员在不需要深刻了解异步编程的底层原理,就可以写出十分优美而又代码量极少的代码。
1393 0