自己实现async和await

  无意当中看了一些博文,说有人想自己尝试实现基于异步操作的方法:

  1)直接使用Task(不说咯,这个是微软给我们的标准实现方法)。

  2)必须继承INotifyCompletion接口,同时自己实现IsCompleted(必须)和Result(可选),GetResult(必须)OnCompleted(必须)方法:

  下面是一个具体的例子(自实现异步函数): 

public interface IAwait<out T> : INotifyCompletion
    {
        bool IsCompleted { get; }
        T Result { get; }
        T GetResult();
    }
    public interface IAwaitable<out T>
    {
        IAwait<T> GetAwaiter();
    }

    public class AwaitableFunc<T> : IAwaitable<T>
    {
        private Func<T> fun = null;

        public IAwait<T> GetAwaiter()
        {
            return new InnerAwaitableImplement(fun);
        }

        public AwaitableFunc(Func<T> func)
        {
            fun = func;
        }

        private class InnerAwaitableImplement : IAwait<T>
        {
            private Func<T> fun = null;
            private bool isFinished=false;
            private T result = default(T);

            public InnerAwaitableImplement(Func<T> func)
            {
                fun = func;
            }
            public bool IsCompleted
            {
                get
                {
                    return isFinished;
                }
            }

            public T Result
            {
                get
                {
                    return GetResult();
                }
            }

            public void OnCompleted(Action continuation)
            {
                ThreadPool.QueueUserWorkItem(obj => 
                {
                    isFinished = true;
                    continuation();
                }, null);
            }


            public T GetResult()
            {
                result = fun();
                return result;
            }
        }
    }

GetResult和Result属性应该实现同步的方法(阻塞线程的),OnCompleted实现异步方法(必须新线程去处理)。这样的话,一旦主程序这样调用:

AwaitableFunc<int> afunc = new AwaitableFunc<int>(() =>
            {
                //模拟一个长时间的任务,注意这里如果用同步机器就死掉
                Thread.Sleep(5000);
                return 1;
            });

            var result =  afunc.GetAwaiter();

            result.OnCompleted(() =>
            {
                MessageBox.Show(result.GetResult().ToString());
            });

你会发现,GetAwaiter方法会先被执行,判断IsCompleted是否为false,如果是false,先执行OnCompleted的方法(作为回调函数一样的性质)先保留,然后开辟新线程执行GetResult(),最后回调到OnCompleted执行回调函数。

你也可以这样调用:

private  async void button1_Click(object sender, EventArgs e)
        {
            AwaitableFunc<int> afunc = new AwaitableFunc<int>(() =>
            {
                //模拟一个长时间的任务,注意这里如果用同步机器就死掉
                Thread.Sleep(5000);
                return 1;
            });

            var result = await afunc;
            MessageBox.Show(result.ToString());
        }

类似于第一个示例(这里就指出了await其实本质是一个回调函数,编译器自动把await下面的东西全部包含到里边去了,简单叙述原理,注意代码中红色标示部分的位置!)。

其实,GetResult并不是一定需要的,比如这个对int任意进行延时(不直接调用Task.Delay方法,自己写一个呗):

public class TimeDelay
    {
        private int _delayTime = 0;

        public TimeDelay(int delayNumber)
        {
            _delayTime = delayNumber;
        }
        public InnerAwaitableImplement GetAwaiter()
        {
            return new InnerAwaitableImplement(_delayTime);
        }
        public class InnerAwaitableImplement:INotifyCompletion
        {
            private int _delayTime = 0;
            private bool isFinished=false;

            public InnerAwaitableImplement(int delayTime)
            {
                _delayTime = delayTime;
            }
            public bool IsCompleted
            {
                get
                {
                    return isFinished;
                }
            }
            public void OnCompleted(Action continuation)
            {
                ThreadPool.QueueUserWorkItem(obj => 
                {
                    Thread.Sleep(_delayTime);
                    isFinished = true;
                    continuation();
                }, null);
            }


            public void GetResult()
            {
                
            }
        }
    }

这样使用:

private async void button1_Click(object sender, EventArgs e)
        {
            TimeDelay afunc = new TimeDelay(2500);
            await afunc;
            MessageBox.Show("OK");
        }

更简单地——扩展方法:

public class TimeDelay
    {
        private int _delayTime = 0;

        public TimeDelay(int delayNumber)
        {
            _delayTime = delayNumber;
        }
        public InnerAwaitableImplement GetAwaiter()
        {
            return new InnerAwaitableImplement(_delayTime);
        }
        public class InnerAwaitableImplement:INotifyCompletion
        {
            private int _delayTime = 0;
            private bool isFinished=false;

            public InnerAwaitableImplement(int delayTime)
            {
                _delayTime = delayTime;
            }
            public bool IsCompleted
            {
                get
                {
                    return isFinished;
                }
            }
            public void OnCompleted(Action continuation)
            {
                ThreadPool.QueueUserWorkItem(obj => 
                {
                    Thread.Sleep(_delayTime);
                    isFinished = true;
                    continuation();
                }, null);
            }


            public void GetResult()
            {
                
            }
        }
    }

    public static class IntExtend
    {
        public static TimeDelay.InnerAwaitableImplement GetAwaiter(this int delayTime)
        {
            TimeDelay td = new TimeDelay(delayTime);
            return td.GetAwaiter();
        }
    }

这样调用:

private async void button1_Click(object sender, EventArgs e)
        {await 1000;
            MessageBox.Show("OK");
        }
posted @ 2014-08-17 13:55  Serviceboy  阅读(1462)  评论(0编辑  收藏  举报