自己实现async和await

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

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

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

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

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

publicinterfaceIAwait<outT>: INotifyCompletion

{boolIsCompleted {get; }

T Result {get; }

T GetResult();

}publicinterfaceIAwaitable<outT>{

IAwait<T>GetAwaiter();

}publicclassAwaitableFunc<T> : IAwaitable<T>{PRivateFunc<T> fun =null;publicIAwait<T>GetAwaiter()

{returnnewInnerAwaitableImplement(fun);

}publicAwaitableFunc(Func<T>func)

{

fun=func;

}privateclassInnerAwaitableImplement : IAwait<T>{privateFunc<T> fun =null;privateboolisFinished=false;privateT result =default(T);publicInnerAwaitableImplement(Func<T>func)

{

fun=func;

}publicboolIsCompleted

{get{returnisFinished;

}

}publicT Result

{get{returnGetResult();

}

}publicvoidOnCompleted(Action continuation)

{

ThreadPool.QueueUserWorkItem(obj=>{isFinished=true;

continuation();

},null);

}publicT GetResult()

{

result=fun();returnresult;

}

}

}

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

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

});varresult =afunc.GetAwaiter();

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

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

你也可以这样调用:

privateasyncvoidbutton1_Click(objectsender, EventArgs e)

{

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

});varresult =awaitafunc;MessageBox.Show(result.ToString());}

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

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

publicclassTimeDelay

{privateint_delayTime =0;publicTimeDelay(intdelayNumber)

{

_delayTime=delayNumber;

}publicInnerAwaitableImplement GetAwaiter()

{returnnewInnerAwaitableImplement(_delayTime);

}publicclassInnerAwaitableImplement:INotifyCompletion

{privateint_delayTime =0;privateboolisFinished=false;publicInnerAwaitableImplement(intdelayTime)

{

_delayTime=delayTime;

}publicboolIsCompleted

{get{returnisFinished;

}

}publicvoidOnCompleted(Action continuation)

{

ThreadPool.QueueUserWorkItem(obj=>{

Thread.Sleep(_delayTime);

isFinished=true;

continuation();

},null);

}publicvoidGetResult()

{

}

}

}

这样使用:

privateasyncvoidbutton1_Click(objectsender, EventArgs e)

{

TimeDelay afunc=newTimeDelay(2500);awaitafunc;

MessageBox.Show("OK");

}

更简单地——扩展方法:

publicclassTimeDelay

{privateint_delayTime =0;publicTimeDelay(intdelayNumber)

{

_delayTime=delayNumber;

}publicInnerAwaitableImplement GetAwaiter()

{returnnewInnerAwaitableImplement(_delayTime);

}publicclassInnerAwaitableImplement:INotifyCompletion

{privateint_delayTime =0;privateboolisFinished=false;publicInnerAwaitableImplement(intdelayTime)

{

_delayTime=delayTime;

}publicboolIsCompleted

{get{returnisFinished;

}

}publicvoidOnCompleted(Action continuation)

{

ThreadPool.QueueUserWorkItem(obj=>{

Thread.Sleep(_delayTime);

isFinished=true;

continuation();

},null);

}publicvoidGetResult()

{

}

}

}publicstaticclassIntExtend

{publicstaticTimeDelay.InnerAwaitableImplement GetAwaiter(thisintdelayTime)

{

TimeDelay td=newTimeDelay(delayTime);returntd.GetAwaiter();

}

}

这样调用:

privateasyncvoidbutton1_Click(objectsender, EventArgs e)

{await1000;

MessageBox.Show("OK");

}

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航