首页 > 代码库 > 自己实现async和await

自己实现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");        }