Computers can perform operations concurrently.
Tasks that proceed independently of one another are said to execute asynchronously and are referred to as asynchronous tasks.
Only computers that have multiple processors or cores can truly execute multiple asynchronous tasks concurrently.
Visual C# apps can have multiple threads of execution, where each thread has its own method-call stack, allowing it to execute concurrently with other threads while sharing with them application-wide resources such as memory and processors. This capability is called multithreading.
Operating systems on single-core computers create the illusion of concurrent execution by rapidly switching between activities (threads).
Today’s multicore computers, smartphones and tablets enable computers to perform tasks truly concurrently.
Asynchronous programming is a technique for writing apps containing tasks that can execute asynchronously, which can improve app performance and GUI responsiveness in apps with long-running or compute-intensive tasks.
The async
modifier and await
operator greatly simplify asynchronous programming, reduce errors and enable your apps to take advantage of the processing power in today’s multicore computers, smartphones and tablets.
In .NET, many classes for web access, file processing, networking, image processing and more provide methods that return Task
objects for use with async
and await
, so you can take advantage of this new asynchronous programming model.
async
ModifierThe async
modifier indicates that a method or lambda expression contains at least one await
expression.
An async
method executes its body in the same thread as the calling method.
await
ExpressionWhen an async
method encounters an await
expression: If the asynchronous task has already completed, the async
method simply continues executing. Otherwise, program control returns to the async
method’s caller until the asynchronous task completes execution. When the asynchronous task completes, control returns to the async
method and continues with the next statement after the await
expression.
The mechanisms for determining whether to return control to the async
method’s caller or continue executing the async
method, and for continuing the async
method’s execution when the asynchronous task completes, are handled entirely by code that’s written for you by the compiler.
async
, await
and ThreadsThe async
and await
mechanism does not create new threads. The method that you call to start an asynchronous task on which you await
the results is responsible for creating any threads that are used to perform the asynchronous task (e.g., Task
method Run
).
If a long-running calculation were to be performed synchronously in a GUI app, the GUI would freeze until the calculation completed and the user would not be able to interact with the app.
Launching a calculation asynchronously and executing it on a separate thread keeps the GUI responsive.
The recursive implementation of the Fibonacci calculation is a compute-intensive calculation.
calculateButton_Click
A method is declared async
to indicate to the compiler that the method will await
an asynchronous task.
In effect, an async
method allows you to write code that looks as if it executes sequentially, while the compiler deals with the complicated issues of managing asynchronous execution.
Task
Method Run
: Executing Asynchronously in a Separate ThreadA Task
promises to return a result at some point in the future.
Class Task
is part of .NET’s Task Parallel Library (TPL) for parallel and asynchronous programming.
Task static
method Run
receives a Func<TResult>
delegate as an argument and executes a method in a separate thread. The method returns a Task<TResult>
, where TResult
represents the type of value returned by the method being executed.
The Func<TResult>
delegate represents any method that takes no arguments and returns a result of generic type TResult
.
await
ing the ResultTask
property Result
returns the value returned by a Task
.
An async
method can perform other statements between those that launch an asynchronous Task
and await
the Task
’s results. In such a case, the method continues executing those statements after launching the asynchronous Task
until it reaches the await
expression.
You can place the await
expression on the right side of an assignment. The await
operator unwraps and returns the Task
’s result so you can use it directly without accessing the Task
’s Result
property.
Handling short computations in the GUI thread does not cause the GUI to become unresponsive.
An app that performs synchronous tasks on a single-core computer often takes longer to execute than on a multicore computer, because the processor is shared between the app and all the other apps that happened to be executing on the computer at the same time. On the dual-core system, one of the cores could have been handling the “other stuff” executing on the computer, reducing the demand on the core that’s doing the synchronous calculation.
When you run any program, your program’s tasks compete for processor time with the operating system, other programs and other activities that the operating system is running on your behalf. In any app, the time to perform the app’s tasks can vary based on your computer’s processor speed, number of cores and what else is running on your computer.
Executing asynchronous methods in separate threads on a dual-core computer typically takes less time than executing the same tasks sequentially.
Executing asynchronous methods in multiple threads on a single-core processor can actually take longer than simply performing them synchronously, due to the overhead of sharing one processor among the app’s threads, all the other apps executing on the computer at the same time and the chores the operating system was performing.
await
ing Multiple Task
s with Task
Method WhenAll
You can wait for multiple Task
s to complete by await
ing the result of Task static
method WhenAll
, which returns a Task
that waits for all of WhenAll
’s argument Task
s to complete and places all the results in an array. This array can be used to iterate through the results of the await-
ed Task
s.
GUI controls are designed to be manipulated only by the GUI thread—modifying a control from a non-GUI thread can corrupt the GUI, making it unreadable or unusable.
When updating a control from a non-GUI thread, you must schedule that update to be performed by the GUI thread. To do so in Windows Form
s, you check the InvokeRequired
property of class Form
. If this property’s value is true
, the code is executing in a non-GUI thread and must not update the GUI directly. Instead, you call the Invoke
method of class Form
, which receives as an argument a Delegate
representing the update to perform in the GUI thread.
A MethodInvoker
(namespace System.Windows.Forms
) is a Delegate
that invokes a method with no arguments and a void
return type.
await
ing One of Several Tasks with Task
Method WhenAny
Task static
method WhenAny
enables you to wait for any one of several Task
s specified as arguments to complete. WhenAny
returns the Task
that completes first.
HttpClient
A web service is software that can receive method calls over a network using standard web technologies. Because there can be unpredictably long delays while await
ing a web-service response, asynchronous Task
s are frequently used in GUI apps that invoke web services (or perform network communication in general) to ensure that the apps remain responsive.
HttpClient
to Invoke a Web ServiceClass HttpClient
(namespace System.Net.Http
) can invoke a web service. Class HttpClient
is one of many .NET classes that support asynchronous programming with async
and await
.
flickr.photos.search
MethodHttpClient
’s CancelPendingRequests
method terminates its executing asynchronous tasks.
Class HttpClient
’s GetStringAsync
method uses the URL specified as the method’s string
argument to request information from a web server and returns a Task<string>
representing a promise to eventually return a string
.
XML represents data as elements, attributes and text.
XML delimits elements with start tags and end tags.
A start tag consists of the element name, possibly followed by attributeName=value pairs, all enclosed in angle brackets.
An end tag consists of the element name preceded by a forward slash (/
) in angle brackets.
An element’s start and end tags enclose text that represents a piece of data or other nested elements.
If an element is empty—that is, it does not contain text or nested elements between its start and end tags—then the element can be represented by a start tag that ends with />
rather than >
.
Namespace System.Xml.Linq
contains the classes used to manipulate XML using LINQ to XML.
XDocument
method Parse
converts into an XDocument
object a string
of XML.
LINQ to XML can query an XDocument
to extract data from the XML.
XDocument
method Descendants
returns a list of XElement
objects representing the elements with the name specified as an argument.
XElement
method Attribute
extracts XAttributes
representing an element’s attributes.
XAttribute
property Value
returns the value of a given attribute.
ListBox
You cannot bind a LINQ query’s result directly to a ListBox
. You must first convert the results to a List
with method ToList
or to an array with ToArray
.
A ListBox
’s DataSource
property indicates the source of the data that populates the ListBox
’s Items
collection. A ListBox
’s DisplayMember
property indicates which property of each item in the data source should be displayed in the ListBox
.
HttpClient
’s GetByteArrayAsync
method launches in a separate thread a Task<byte[]>
that gets a byte[]
from the URL specified as the method’s string
argument.
ProgressBar
property Minimum
gets or sets a ProgressBar
’s minimum value.
ProgressBar
property Maximum
gets or sets a ProgressBar
’s maximum value.
ProgressBar
property Value
gets or sets a ProgressBar
’s current value. As this number increases, a ProgressBar
fills with color.
Enumerable static
method Repeat
creates a list of elements containing the first argument’s value. The length of the list is specified by the second argument. Repeat
is a generic method—the type of the list it returns is determined by the first argument’s type.