How to Use Async to Increase Winforms Performance

How can I use async to increase WinForms performance?

Yes, you're still doing all the work on the UI thread. Using async isn't going to automatically offload the work onto different threads. You could do this though:

private async void button2_Click(object sender, EventArgs e)
{
string file = files[0];
Task<string> task = Task.Run(() => ProcessFile(file));
rtTextArea.Text = await task;
}

private string ProcessFile(string file)
{
using (TesseractEngine tess = new TesseractEngine("tessdata", "dic",
EngineMode.TesseractOnly))
{
Page p = tess.Process(Pix.LoadFromFile(file));
return p.GetText();
}
}

The use of Task.Run will mean that ProcessFile (the heavy piece of work) is executed on a different thread.

Async loading for winforms

Where am i supposed to place the await keyword to accomplish this? I
can't place it in my Load event since this needs to complete for the
application to behave "normally".

Why can't you await inside load event handler? You can do that if you mark the method with async modifier.

private async void Form_Load(object sender, EventArgs e)
{
//Do something
var data = await GetDataFromDatabaseAsync();
//Use data to load the UI
}

This way, you can keep the UI responsive and also execute the time consuming work asynchronously. GetDataFromDatabaseAsync has to be asynchronous (should not block the calling thread).

If this doesn't answers your question, please be more specific.

Winforms call to async method hangs up program

Your problem is because you are blocking the UI thread when you call .Result and you told the continuation after Task.Delay to run on the UI thread. So you are blocking the UI waiting for a task that is blocked on waiting for the UI to become free, a classic deadlock.

Two solutions. First make the button click async too.

private async void buttonOk_Click(object sender, System.EventArgs e)
{
var asyncResolvedIssue = api.ResolveIssue(issue, revision, pathList);
if (await asyncResolvedIssue) {} // <== no deadlock!
}

Event handlers are the only place you are allowed to do async void.

The other option is tell Task.Delay it does not need to have the rest of its function run on the UI thread by setting ConfigureAwait(bool) to false.

public async Task<bool> ResolveIssue(Issue issue, int revision, string[] pathList)
{
await Task.Delay(1000).ConfigureAwait(false);

return true;
}

Now the line of code after the Task.Delay will run on a threadpool thread instead of the UI thread and will not be blocked by the fact that the UI thread is currently blocked.

Windows Forms async await

The way you are doing it will work just fine. The documentation for Sytem.Timers.Timer says:

If the SynchronizingObject property is null, the Elapsed event is raised on a ThreadPool thread.

The SynchronizingObject property is null by default, so your Elasped event will run on a ThreadPool thread, not on the UI thread. That means it will not stop your application from responding to user input.

If there is a chance that ElapsedTime() will run longer than your interval, and you don't want the events overlapping, then you can set AutoReset to false and reset it manually at the end of ElapsedTime(). Just make sure that everything is wrapped in a try/catch block, otherwise the timer won't get reset if there's an exception. My code below shows how that would look.

You don't need to use async/await anywhere here. Since it won't be running on the UI thread, using asynchronous code won't really help you any. In a desktop app, it's not a big deal to have a separate (non-UI) thread wait.

public class Timer
{

private System.Timers.Timer timer;
private void InitTimer()
{
timer = new System.Timers.Timer(4000);
timer.Elapsed += ElapsedTime;
timer.AutoReset = false;
timer.Enabled = true;
}

private void ElapsedTime()
{
try {
//send request and update data
}
catch (Exception e)
{
//log the error
}
finally
{
//start the timer again
timer.Enabled = true;
}
}
}

Cache table with async method

You need a combination of ToListAsync as the comments suggested and an async OnLoad event handler like below. You won't be able to await in the constructor, and you have to mark your events async void to be able to await in them.

private List<Item> itemsList = null;

public Form1()
{
InitializeComponent();
Load += OnLoad;
}

private async void OnLoad(object sender, EventArgs eventArgs)
{
itemsList = await dataContext.Items.Where(x => x.Active == true).ToListAsync();
}

Do nested async/await calls give any performance boost?

Task.Run only serves to run your code on the thread pool. This can be useful for WPF or WinForms applications, since it frees up the UI thread to continue processing other UI events. However, it does not bring any performance benefits in ASP.NET, since you're just switching execution from one thread-pool thread to another. When it encounters the EF ToList call, this thread-pool thread will get blocked. If you have a lot of concurrent requests, the thread pool will get exhausted. .NET has a thread injection policy, but this is limited, so some requests will time out. If your load gets very high, you will need so many threads that you will deplete your system resources (CPU and memory).

By contrast, async-all-the-way means that you are never blocking any threads while the database I/O operations are in progress. Each asynchronous operation is handled by the underlying system, and execution only resumes on the thread pool once the operation has completed. This allows your system to scale to a much larger number of concurrent requests.



Related Topics



Leave a reply



Submit