Improve the responsiveness of your application without increasing the complexity of your code in Synergy/DE 10.1
Sometimes with large applications, we have sections of code that are not as responsive as we’d like them to be, such as code that retrieves information from the web. As a result, an application can appear to hang, and so we resort to adding a graphic, such as progress bar, to indicate that work is actually being done. This is a nice way to prevent the user from aborting, but what if the application could make the web request and continue on with other work, going back to get the results only after the retrieval was complete?
That’s the goal of asynchronous programming. Traditional techniques for doing this type of programming can be painful, in that they require a lot of development work to maintain the state of the request within the application. In Synergy .NET version 10.1, however, we’ve greatly simplified asynchronous programming by adding support for two new keywords: ASYNC and AWAIT.
Adding an ASYNC modifier to a method indicates that it is an asynchronous method, which is a non-blocking operation. Within an asynchronous method, we can then use the AWAIT statement on asynchronous tasks that need to be waited for within the method. These AWAIT statements denote suspension points within the ASYNC method; if the task is not done, the method is exited immediately so other application work can continue. When the awaited task is complete, the application returns to that spot and continues the application logic within the ASYNC method until it either reaches another AWAIT suspension point or the method completes.
Using ASYNC requires .NET Framework 4.5. The return type for the ASYNC method must be Task or Task<T> (which are .NET Framework classes that contain information to indicate when a task is complete) or void. Also, the expression following AWAIT must give a Task-based result.
In the code below, the clickit() method is marked ASYNC and has three awaited tasks that get the titles of unique web pages. This program can be compiled using Synergy .NET 10.1 with the following command line:
dblnet -ref=System.Windows.Forms.dll,System.Drawing.dll <myprogram.dbl>
import System import System.Windows.Forms import System.Net import System.Text.RegularExpressions namespace WindowsFormsApplication1 class Form1 extends Form public method Form1 proc InitializeComponent() end private method InitializeComponent, void proc this.listBox1 = new System.Windows.Forms.ListBox() this.button1 = new System.Windows.Forms.Button() this.SuspendLayout() this.listBox1.FormattingEnabled = true this.listBox1.Location = new System.Drawing.Point(51, 82) this.listBox1.Name = "listBox1" this.listBox1.Size = new System.Drawing.Size(200, 147) this.listBox1.TabIndex = 0 this.button1.Location = new System.Drawing.Point(100, 26) this.button1.Name = "button1" this.button1.Size = new System.Drawing.Size(75, 23) this.button1.TabIndex = 1 this.button1.Text = "Get Titles" this.button1.UseVisualStyleBackColor = true this.button1.Click += new System.EventHandler(this.button1_Click) this.Controls.Add(this.button1) this.Controls.Add(this.listBox1) this.Name = "Form1" this.Text = "URI Titles" this.ResumeLayout(false) end private listBox1, @System.Windows.Forms.ListBox private button1, @System.Windows.Forms.Button private method button1_Click, void sender, @* e, @EventArgs proc listBox1.Items.Add("work before") clickit() listBox1.Items.Add("work after") end public async method clickit, void proc data wc1, @WebClient, new WebClient() WriteLinePageTitle(await wc1.DownloadStringTaskAsync(new Uri("http://www.weather.gov"))) WriteLinePageTitle(await wc1.DownloadStringTaskAsync(new Uri("https://www.synergex.com"))) WriteLinePageTitle(await wc1.DownloadStringTaskAsync(new Uri("http://www.microsoft.com"))) end public method WriteLinePageTitle, void page, string proc listBox1.Items.Add(GetPageTitle(page)) end public method GetPageTitle, string page, string proc data titleRegex, @Regex, new Regex("\<title\>(?<title>.*)\<\/title\>", RegexOptions.IgnoreCase) data match = titleRegex.Match(page) if (match.Success) then begin mreturn "Page title: " + match.Groups["title"].Value end else begin mreturn "Page has no title" end end endclass endnamespace main proc Application.EnableVisualStyles() Application.SetCompatibleTextRenderingDefault(false) Application.Run(new Form1()) end
When running this program, clicking on the “Get Titles” button causes button1_click() to execute. This causes “work before” to be output, followed by a call to clickit(). Because clickit() is designated ASYNC, the routine executes all the way up to the first AWAIT statement. Since the task for that first AWAIT is not complete, clickit() is exited, and execution within button1_click() continues, causing “work after” to be displayed. Once the first AWAIT statement in clickit() is complete, the execution of clickit() displays the first page title. Then execution continues up to the next AWAIT statement. After the second task is complete, the second title is displayed, and execution continues up to the next AWAIT. After the third AWAIT task is complete, the third title is displayed. To accomplish all of this, the compiler generates a lot of code to maintain state — code that you would have had to write manually before the introduction of these two very helpful keywords.
In short, AWAIT and ASYNC can be used to improve the responsiveness of your application without increasing the complexity of your code. If you would like more background on asynchronous programming, check out this article on Microsoft’s web site.