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
How Are Nullable Types Implemented Under the Hood in .Net
Custom Xmlwriter to Skip a Certain Element
How to Use System.Net.Httpclient to Post a Complex Type
How to Copy File - Access to the Path Is Denied
What Is the Meaning of "This" in C#
How to Add Custom Http Header for C# Web Service Client Consuming Axis 1.4 Web Service
Get Iprincipal from Oauth Bearer Token in Owin
How to Use Transactionscope in C#
Rotate a Graphics Bitmap at Its Center
Why Can't I Use Interface with Explicit Operator
When Not to Use Yield (Return)
Wcf - Design Parameter Decision
Collection Was Modified; Enumeration May Not Execute Error When Removing a Listitem from a Listbox
How to Maximize the Browser Window in Selenium Webdriver (Selenium 2) Using C#
Convert List to Dictionary Using Linq and Not Worrying About Duplicates
Resize Wpf Window and Contents Depening on Screen Resolution