Introduction
While working on a UI application, many of us might have faced the problem of unresponsiveness. This issue generally occurs if one is loading huge data or populating too much data in UI controls. So, in this case, UI will be unresponsive, until the entire data gets loaded into UI controls. In technical words, we can say, it happens, if UI controls are populated in a synchronous manner. Here, the solution is pretty easy, as one can suggest, let’s go for asynchronous pattern. I too emphasis on this.
.NET Fx provides a very comfortable way of doing this asynchronous programming. But before Fx 4.5, it was a bit lengthier approach. But as we all know, Microsoft loves to put too much effort in optimization and performance issues. The same happened here as well. It come out with .NET 4.5 BCL, which provides a comfortable as well as a very short way to do this asynchronous programming.
Today, I’ll take a sample scenario, in which first I’ll show you the traditional way of converting Synchronous example to Asynchronous one and then we will see how the same can be accomplished using Fx 4.5.
Using the Code
Synchronous Pattern
public void CopySynchronously(Stream source, Stream destination)
{
byte[] buffer = new byte[0x1000];
int numberOfBytes;
while ((numberOfBytes = source.Read(buffer, 0, buffer.Length)) != 0)
{
destination.Write(buffer, 0, numberOfBytes);
}
}
After looking at synchronous pattern, let's check out the asynchronous one. The biggest problem with traditional Asynchronous Programming Model (APM) was that it was mandatory to surround the code block within Begin/End pair.
Now let’s have a look at the below snippet, which will write the asynchronous version of the above snippet in a traditional APM way:
Asynchronous Pattern (APM)
public void CopyAsynchronously(Stream source, Stream destination)
{
byte[] buffer = new byte[0x1000];
Action<IAsyncResult> readWriteLoop = null;
readWriteLoop = iar =>
{
for (bool isRead = (iar == null); ; isRead = !isRead)
{
switch (isRead)
{
case true:
iar = source.BeginRead(buffer, 0, buffer.Length, readResult =>
{
if (readResult.CompletedSynchronously) return;
readWriteLoop(readResult);
}, null);
if (!iar.CompletedSynchronously) return;
break;
case false:
int numberOfBytes = source.EndRead(iar);
if (numberOfBytes == 0)
{
return;
}
iar = destination.BeginWrite(buffer, 0, numberOfBytes, writeResult =>
{
if (writeResult.CompletedSynchronously) return;
destination.EndWrite(writeResult);
readWriteLoop(null);
}, null);
if (!iar.CompletedSynchronously) return;
destination.EndWrite(iar);
break;
}
}
};
readWriteLoop(null);
}
By looking at the above snippet, one can conclude that it is not that simple to understand. So, to bring simplicity into the existing APM, Microsoft comes up with a new version of APM, in Fx 4.5 BCL. This new APM is based on Task
and Task<T>
with support of async
and await
keywords. Now we will quickly move to this new feature snippet:
Asynchronous Pattern using Fx 4.5
public async Task CopyToAsync(Stream source, Stream destination)
{
byte[] buffer = new byte[0x1000];
int numberOfBytes;
while ((numberOfBytes = await
source.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
await destination.WriteAsync(buffer, 0, numberOfBytes);
}
}
So, here we can see that two new keywords make our entire thing pretty easy.