码迷,mamicode.com
首页 > Windows程序 > 详细

C# 8.0 抢先看-- Async Stream

时间:2018-12-22 20:47:19      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:amr   run   path   lse   har   wait   完成后   null   res   

异步流?

Async Stream 简单说来是一种非同步的迭代器模式,说更白一点就是可以await 的foreach。在过去的C# 中如果要回传一个可迭代的IEnumerable<T> ,我们可能会这样写:

    public class EnumerableProcess
    {
        async static public Task<IEnumerable<string>> ReadLineAsync(string path)
        {           
            List<string> list = new List<string>();
            using (StreamReader reader = File.OpenText(path))
            {
                while (await reader.ReadLineAsync() is string result)
                {
                    list.Add(result);
                    await Task.Delay(100);
                }
            }
            return list;
        }
    }

  这是一个非同步一行一行读取文字档的例子,这个例子里的回传型别是一个Task<IEnumerable<string>>   ,外部程式码将会这样呼叫这个方法:

 var r = await EnumerableProcess.ReadLineAsync(path);
 foreach (var item in r)
 {
     Console.WriteLine(item);
 }

  

这造成一个长时等待的问题,因为呼叫端必须等待ReadLineAsync 这个Task 整个完成后才能回传;所以C# 8.0 引入了Async Stream 使得非同步的迭代得以实现, 这件事情不仅仅牵涉到编译器,也需要一些新的型别,主要是以下三个:

(1) IAsyncDisposable -- IAsyncEnumerator<out T> 将会拓展这个介面

public interface IAsyncDisposable
{
    ValueTask DisposeAsync();
}

(2)IAsyncEnumerator <out T>

public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
    T Current { get; }

    ValueTask<bool> MoveNextAsync();
}   

(3)IAsyncEnumerable <out T>

public interface IAsyncEnumerable<out T>
{
    IAsyncEnumerator<T> GetAsyncEnumerator();
}

实作Async Stream

由于此时在框架中对于整个Async Stream 的实作尚未完整,所以没办法直接使用yield return,先示范最基本的写法,建立一个类别,并且实作以上介面:

    sealed class AsyncFileProcess : IAsyncEnumerable<string>, IAsyncEnumerator<string>
    {
        private readonly StreamReader _reader;

        private bool _disposed;
        public AsyncFileProcess(string path)
        {
            _reader = File.OpenText(path);
            _disposed = false;
        }

        public string Current { get; private set; }
        public IAsyncEnumerator<string> GetAsyncEnumerator()
        {
            return this;
        }
        async public ValueTask<bool> MoveNextAsync()
        {
            await Task.Delay(100);            
            var result = await _reader.ReadLineAsync();
            Current = result;
            return result != null;
        }

        async public ValueTask DisposeAsync()
        {
            await Task.Run(() => Dispose());
        }

        private void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!this._disposed)
            {
                if (_reader != null)
                {
                    _reader.Dispose();
                }
                _disposed = true;
            }
        }
    }

呼叫端就可以这样呼叫它:

var process = new AsyncFileProcess("SourceFile.txt");
try
{
    await foreach (var s in process)
    {
        Console.WriteLine(s);
    }
   
    Console.ReadLine();
}
finally
{
    await process.DisposeAsync();
}

你可以感受到第一个例子是停顿了很久之后,蹦一下全跳出来;而第二的例子则会一行行跑出来(为了强化这个效果在两方都加了Task.Delay )。在第二个例子的呼叫端可以看到await foreach 的使用。

C# 8.0 抢先看-- Async Stream

标签:amr   run   path   lse   har   wait   完成后   null   res   

原文地址:https://www.cnblogs.com/wwwblender-3dcn/p/10162224.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!