Upload
yuyijq
View
988
Download
1
Embed Size (px)
DESCRIPTION
.NET平台上的异步编程风格的变化,从传统的异步编程,到利用第三方类库以及新出现的F#异步工作流,还有未来.NET 5.0中的TAP
Citation preview
Yu Zhaohui
http://yuyijq.cnblogs.com
.NET平台上的异步编程
• 余昭辉,网名横刀天笑• http://yuyijq.cnblogs.com
• Programming language fans
• Design Pattern & Architecture
• .NET CLR
• C# MVP
90%以上的应用都是在以错误的方式使用线程 - Jeffrey Richter
Write async program is hard, and write stable program is even harder.
private void btnDownload_Click(object sender, EventArgs e){
try{var request = HttpWebRequest.Create(“http://yuyijq.cnblogs.com”);var response = request.GetResponse();using(var stream = response.GetResponseStream()){
return stream.ReadToEnd();}
}catch{//…}}
var request = HttpWebRequest.Create(“http://yuyijq.cnblogs.com”);request.BeginGetResponse(DownloadCompeleted,request);
public void DownloadCompeleted(IAsyncResult ar){
var request = (HttpWebRequest)ar.AsyncState;var response = request.EndGetResponse();var stream = response.GetResponseStream();ReadHelper(stream);
}public void ReadHelper(Stream stream){
byte[] buffer = new byte[1024];stream.BeginRead(buffer,0,1024,(ar) =>{
var actualRead = stream.EndRead();if(actualRead == 0){
stream.Close();}else{
//proccess dataReadHelper(stream);
}},null);
}
传统异步的异步编程
• For, while 等基本构造无法使用• Try catch无法使用,异常处理非常困难• Using无法使用,代码变糟• 所有异步方法分为二段式:发起请求和请求结束处理。代码进一步腐化
这样造成的结果是:放弃效率更高的异步方式,采用效率低的同步方式
其实我们要寻找的是一种获得 continue的方式:
Continution Passing Style
Print(Add(5,6))
void Print(int result){ Console.WriteLine(result);}int Add(int l, int r){
return l + r;}
Add(5, 6, (ret) => Print(ret));
void Add(int l, int r, Action<int> continue){
continue(l + r);}
神奇的 yield
Private IEnumerator<int> Caclute(){
int i = 5 + 6;yield return 1;Console.WriteLine(i);i = 4 * 5;yield return 1;Console.WriteLine(i);//…
}
Private Ienumerator<int> Caclute(){
return new StateMachine();}
Public class StateMachine{ public bool MoveNext() {
switch(state){ case 0: //…}
}}
While(Caclute().MoveNext()){//…
}
如是我们可以这样编写异步代码:Private Ienumerator<int> Download(){
var req = HttpWebRequest.Create(“http://yuyijq.cnblogs.com”);var ar1 = req.BeginGetResponse(__?__,null);yield return 1;var resp = req.EndGetResponse(ar1);using(var stream = resp.GetResponseStream()){
byte[] buffer = new byte[1024];do{ var ar2 =stream.BeginRead(buffer,0,1024,__?__,null); yield return 1; var actualRead = stream.EndRead(ar2);}while(actualRead != 0)
}}
self.MoveNext
self.MoveNext
AsyncRunner runner = new AsyncRunner();Runner.Run(Download(runner));
Public void Run(Ienumerator<int> async){
this.async = async;async.MoveNext();
}
Public AsyncCallback Continue(){
return (ar) => this.async.MoveNext();}
Private Ienumerator<int> Download(AsyncRunner runner){
var req = HttpWebRequest.Create(“http://yuyijq.cnblogs.com”);var ar1 = req.BeginGetResponse(runner.Continue,null);yield return 1;var resp = req.EndGetResponse(ar1);using(var stream = resp.GetResponseStream()){
byte[] buffer = new byte[1024];do{ var ar2 =stream.BeginRead(buffer,0,1024,runner.Continue,null); yield return 1; var actualRead = stream.EndRead(ar2);}while(actualRead != 0)
}}
第三方类库支持
• Jeffrey Ritcher 的 AsyncEnumerator
• CCR 的 Iterator
• Rx(reactive programming)
F#简介• 由微软剑桥研究院的 Don Syme开发• 静态的,强类型的,基于 .NET平台的函数式编程语言• 历史基于和 .NET一样长• 起源于 Ocame
F# ASYNC WORKFLOW
def download url = async{ let req = WebRequest.Create(url) let! resp = req.AsyncGetResponse() use stream = resp.GetResponseStream() use reader = new StreamReader(stream) let! content = reader.AsyncReadToEnd() return content }
builder.Delay( var req = WebRequest.Create(url); builder.Bind(req.AsyncGetReponse(),(resp) =>{ builder.Using(resp.GetResponseStream(),(stream) =>{ builder.Using(new StreamReader(stream),(reader) =>{ builder.Bind(reader.AsyncReadToEnd(),(content) =>{ builder.Return(content); }) }) }) }) );
F# WORKFLOW
type Async<‘T>
type AsyncBuilder with member Return : ‘T -> Async<‘T> member Delay : (unit -> Async<‘T>) -> Async<‘T> member Using : ‘T * (‘T -> Async<‘U>) -> Async<‘U> when ‘T :> System.Idisposable member Bind : Async<‘T> * (‘T -> Async<‘U>) -> Async<‘U>
let async = new AsyncBuilder
async{ let!...}
.NET 5.0 TAP
Public async String Download(String url){ var req = WebRequest.Create(url); var resp = await req.GetResponseAsync(); using(var stream = resp.GetResponseStream()) { }}
Asynchrony doesn't mean "background thread”
Lucian Wischik
Thank you