代码改变世界

异步编程相关的APM、Lambda、CCR、AsyncEnumerator(CLR)

2011-12-19 17:43  木木子  阅读(499)  评论(0编辑  收藏  举报

传统异步编程操作

.NET平台的异步编程方式是APM(Asynchronous Programing Model,异步编程模式)。就是常见的BeginOperation和EndOperation二段式调用,并使用回调函数(AsyncCallback)和异步状态(IAsyncResult)。简单例子:

FileStream fs = new FileStream(@"C:\Data.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 8192, FileOptions.Asynchronous);
 
Byte[] data = new Byte[fs.Length];
fs.BeginRead(data, 0, data.Length, result =>
{
    int byteRead = fs.EndRead(result);
    Process(data);
    fs.Close();
}, null);

上述代码就是简单的使用了APM。有不足之处,就是需要显示的调用fs.close()方法,而不能使用using。例子中还使用了Lambda,使用Lambda的好处在于,能够访问到外部方法的局部变量。

传统操作的不利

APM使用两段式来实现异步操作,这样使得不能使用using、try…catch…finally。更不好的是,我要是两件有前后顺序的操作要异步执行,那代码会变的怎么样:

FileStream fs = new FileStream(@"C:\Data.txt", FileMode.Open, FileAccess.Read, FileShare.Read, 8192, FileOptions.Asynchronous);
 
Byte[] data = new Byte[fs.Length];
fs.BeginRead(data, 0, data.Length, readResult =>
{
    int byteRead = fs.EndRead(readResult);
 
    fs.BeginWrite(data, 0, data.Length, writeResult=>
    {
        fs.EndWrite(writeResult);
        Process(data);
    }, null);
 
    Process(data);
    fs.Close();
}, null);

两个异步操作相互嵌套,看起来真的很累啊。假如这种有前后顺序的操作更多呢,这将是一段恐怖的代码。

CCR

CCR中用到了基于迭代器(Iterator)的异步开发方式。使用yield关键字,很好的解决了这种有顺序的异步操作。看个例子:

static IEnumerable<int> ApmPatternWithIterator()
{
    using (FileStream fs = new FileStream(@"C:\kbdlyot.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 8192, FileOptions.Asynchronous))
    {
        Byte[] data = new Byte[fs.Length];
        fs.BeginRead(data, 0, data.Length, readResult =>
        {
            int byteRead = fs.EndRead(readResult);
            Process(data);
        }, null);
 
        yield return 1;
 
        fs.BeginWrite(data, 0, data.Length, writeResult =>
        {
            fs.EndWrite(writeResult);
            Process(data);
        }, null);
 
        yield return 1;
    }
}

上述的异步执行,不仅省去了相互嵌套的复杂,还能够使用using之类的关键字。

AsyncEnumerator

AsyncEnumerator是Jeffrey开发的,在Wintellect's .NET Power Threading Library中。AsyncEnumerator在功能上比CCR更完善。

用AsyncEnumerator修改上面的例子:

static IEnumerable<int> ApmPatternWithAsyncEnumerator(AsyncEnumerator enumerator)
{
    using (FileStream fs = new FileStream(@"C:\kbdlyot.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 8192, FileOptions.Asynchronous))
    {
        Byte[] data = new Byte[fs.Length];
        fs.BeginRead(data, 0, data.Length, enumerator.End(), null);
 
        yield return 1;
        var res =  fs.EndRead(enumerator.DequeueAsyncResult());
 
        fs.BeginWrite(data, 0, data.Length, enumerator.End(), null);
 
        yield return 1;
 
        Process(data);
    }
}

 

 

参考:

老赵-简化异步操作(上):使用CCR和AsyncEnumerator简化异步操作