本身實現async和await

  無心當中看了一些博文,說有人想本身嘗試實現基於異步操做的方法:異步

  1)直接使用Task(不說咯,這個是微軟給咱們的標準實現方法)。async

  2)必須繼承INotifyCompletion接口,同時本身實現IsCompleted(必須)和Result(可選),GetResult(必須)OnCompleted(必須)方法:函數

  下面是一個具體的例子(自實現異步函數): this

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實現異步方法(必須新線程去處理)。這樣的話,一旦主程序這樣調用:spa

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執行回調函數。線程

你也能夠這樣調用:code

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下面的東西所有包含到裏邊去了,簡單敘述原理,注意代碼中紅色標示部分的位置!)。blog

其實,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");
        }
相關文章
相關標籤/搜索