A while ago, marc wrote about our “await” keyword added in Oxygene 5.1. “Await” is a new language element for the .NET 4.5 framework that essentially lets you write sequential code without blocking the main thread. It’s actually pretty amazing, in that the compiler will split up your code so the asynchronous parts can run in a thread and then return execution to the main thread when it’s done. A simple example of this would be to do an HTTP request to our blog to grab the lastBuildDate field (the last time a new item was posted or updated).
The code you would write for that could look something like this:
method MainForm.button1_Click(sender: System.Object; e: System.EventArgs);beginvar lClient :=new HttpClient();{ a }var lResponse := await lClient.GetAsync('http://blogs.remobjects.com/feed');{ b } MessageBox.Show( String.Format('The RemObjects blog was last updated at {0}', XDocument.Parse(await lResponse.Content.ReadAsStringAsync).Descendants('lastBuildDate').FirstOrDefault():Value));end; |
If you wrote something similar without await and using synchronous APIs, your application would block and appear hung when the user clicks the button, since both parts of this request can take a while to execute. Pre-“await”, you could/should have opted to use existing asynchronous APIs, but they would have required to write code that is much more convoluted, involving anonymous methods and callbacks.
“Await” lets you write this code the “naïve” way, as simple, straight-forward sequential actions, and the compiler takes care of making things run in separate threads for you.
What really happens here is this (reformatted the names for readability):
method MainForm.button1_Click(sender: System.Object; e: System.EventArgs);beginvar worker :=new MainForm.button1_Click_worker(sender, e,self); worker.Run;// your Button Click event is done here and your application is responsive right away.end; |
method MainForm.Button1_Click_worker.Run;beginvar lBeforeFirstAwait :=false;trycase fState of0:begin fState :=-1;// If an exception occurs, we should never return here. lBeforeFirstAwait :=true; lClient =new HttpClient();{ a } fAwaiter :=self.Client.GetAsync('http://blogs.remobjects.com/feed').GetAwaiter();{ begin of b }if fAwaiter.IsCompletethenbegin{pseudo} goto case element 1;end; fState :=1;// It's not complete; this will make sure we jump to // case element 1 when it is done. The awaiter // will make sure it returns to the main thread. fAwaiter.OnComplete(@Run);exit;end;1:begin// At this point we have the result of the HTTP request. fState :=-1; lResponse := TaskAwaiter |