Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValueTask example code #1

Open
whuanle opened this issue Dec 3, 2020 · 0 comments
Open

ValueTask example code #1

whuanle opened this issue Dec 3, 2020 · 0 comments

Comments

@whuanle
Copy link
Owner

whuanle commented Dec 3, 2020

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;

namespace ConsoleApp12
{
    public class 假的Socket
    {
        private bool IsHaveSend = false;

        // 模拟 Socket 向服务器发送数据
        public void Send(byte[] data)
        {
            new Thread(() =>
            {
                Thread.Sleep(100);
                IsHaveSend = true;
            }).Start();
        }

        // 同步阻塞等待服务器的响应
        public byte[] Receive()
        {
            // 模拟网络传输的数据
            byte[] data = new byte[100];

            while (!IsHaveSend)
            {
                // 服务器没有发送数据到客户端时,一直空等待
            }

            // 模拟网络接收数据耗时
            Thread.Sleep(new Random().Next(0, 100));
            new Random().NextBytes(data);
            IsHaveSend = false;
            return data;
        }
    }

    // Redis 客户端
    public class RedisClient
    {
        // 队列
        private readonly Queue<MyValueTaskSource<string>> queue = new Queue<MyValueTaskSource<string>>();

        private readonly 假的Socket _socket = new 假的Socket();  // 一个 socket 客户端

        public RedisClient(string connectStr)
        {
            new Thread(() =>
            {
                while (true)
                {
                    byte[] data = _socket.Receive();
                    // 从队列中拿出一个状态机
                    if (queue.TryDequeue(out MyValueTaskSource<string> source))
                    {
                        // 设置此状态机的结果
                        source.SetResult(Encoding.UTF8.GetString(data));
                    }
                }
            }).Start();
        }

        private void SendCommand(string command)
        {
            Console.WriteLine("客户端发送了一个命令:" + command);
            _socket.Send(Encoding.UTF8.GetBytes(command));
        }

        public async ValueTask<string> GetStringAsync(string key)
        {
            // 自定义状态机
            MyValueTaskSource<string> source = new MyValueTaskSource<string>();
            // 创建异步任务
            ValueTask<string> task = new ValueTask<string>(source, 0);

            // 加入队列中
            queue.Enqueue(source);

            // 发送获取值的命令
            SendCommand($"GET {key}");

            // 直接使用 await ,只会检查移除状态!一层必须在检查之前完成任务,然后 await 后会陷入无限等待中!
            // return await task;

            // 要想真正实现这种异步,必须使用 SynchronizationContext 等复杂的结构逻辑!
            // 为了避免过多代码,我们可以使用下面这种 无限 while 的方法!
            var awaiter = task.GetAwaiter();
            while (!awaiter.IsCompleted) { }

            // 返回结果
            return await task;
        }
    }

    class Program
    {
        static async Task Main(string[] args)
        {
            // 创建 redis 客户端
            RedisClient redis = new RedisClient("127.0.0.1:6379");

            // 向服务端发送获取值的请求
            string value = await redis.GetStringAsync("痴者工良");
            Console.WriteLine(value);
            Console.ReadKey();
        }
    }

    // 一个可以将同步任务、不同线程同步操作,通过状态机构建异步方法
    public class MyValueTaskSource<TRusult> : IValueTaskSource<TRusult>
    {
        // 存储返回结果
        private TRusult _result;
        private ValueTaskSourceStatus status = ValueTaskSourceStatus.Pending;

        // 此任务有异常
        private Exception exception;

        #region 实现接口,告诉调用者,任务是否已经完成,以及是否有结果,是否有异常等
        // 获取结果
        public TRusult GetResult(short token)
        {
            // 如果此任务有异常,那么获取结果时,重新弹出
            if (status == ValueTaskSourceStatus.Faulted)
                throw exception;
            // 如果任务被取消,也弹出一个异常
            else if (status == ValueTaskSourceStatus.Canceled)
                throw new TaskCanceledException("此任务已经被取消");

            return _result;
        }

        // 获取状态,这个示例中,用不到令牌 token
        public ValueTaskSourceStatus GetStatus(short token)
        {
            return status;
        }

        // 实现延续
        public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
        {
            // 不需要延续,不实现此接口
        }

        #endregion

        #region 实现状态机,能够控制此任务是否已经完成,以及是否有异常

        // 以及完成任务,并给出结果
        public void SetResult(TRusult result)
        {
            status = ValueTaskSourceStatus.Succeeded;  // 此任务已经完成
            _result = result;
        }

        // 取消任务
        public void Cancel()
        {
            status = ValueTaskSourceStatus.Canceled;
        }

        // 要执行的任务出现异常
        public void SetException(Exception exception)
        {
            this.exception = exception;
            status = ValueTaskSourceStatus.Faulted;
        }

        #endregion

    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant