zoukankan      html  css  js  c++  java
  • C# 8.0 抢先看-- Async Stream

    异步流?

    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 的使用。

  • 相关阅读:
    【Go语言】I/O专题
    【Go语言】集合与文件操作
    【Go语言】LiteIDE使用的个人使用方法
    【Go语言】错误与异常处理机制
    【Go语言】面向对象扩展——接口
    【Go语言】学习资料
    创建型模式(前引)简单工厂模式Simple Factory
    redis demo
    导出CSV格式
    mongo聚合命令
  • 原文地址:https://www.cnblogs.com/wwwblender-3dcn/p/10162224.html
Copyright © 2011-2022 走看看