Asynchronous Programming

Improve the responsiveness of your application without increasing the complexity of your code in Synergy/DE 10.1

By Jim Sahaj, Senior Systems Software Engineer

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("http://www.synergex-testsite.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.

For more information about the ASYNC qualifier and the AWAIT statement, see METHOD and AWAIT in the Synergy/DE documentation.

See Synergy/DE 10.1 for more information.