
·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> 自己实现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");
}