i was doing some processor heavy task and every time i start executing that command my winform freezes than i cant even move it around until the task is completed. i used the same procedure from microsoft but nothing seem to be changed.
my working environment is visual studio 2012 with .net 4.5
private async void button2_Click(object sender, EventArgs e)
{
Task<string> task = OCRengine();
rtTextArea.Text = await task;
}
private async Task<string> OCRengine()
{
using (TesseractEngine tess = new TesseractEngine(
"tessdata", "dic", EngineMode.TesseractOnly))
{
Page p = tess.Process(Pix.LoadFromFile(files[0]));
return p.GetText();
}
}
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.
You can also do this by starting your task in new thread.
Just use Thread.Start or Thread. ParameterizedThreadStart
See these for your reference:
http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx
Start thread with parameters
You could use BackgroundWorker component.
Related
I am new to Async and Await and have created a simple project in order to understand how it works.
For this, I have a simple Windows Form application that has 2 elements:
Get Completed Items button
TextBox showing all Completed Items retrieved
When I click the button, it should display all completed Items in the TextBox.
This is the code I have written:
private async void btnGetCompletedItems_Click(object sender, EventArgs e)
{
QueueSystem queueSystem = QueueSystem.NewInstance(75);
Stopwatch watch = new Stopwatch();
watch.Start();
await Task.Run(() => GetCompletedItems(queueSystem));
watch.Stop();
lblTime.Text = $"{watch.ElapsedMilliseconds.ToString()} ms";
}
private void GetCompletedItems(QueueSystem queueSystem)
{
foreach (var item in queueSystem.GetCompletedItems())
{
txtItems.Text += $"{txtItems.Text}{item.ItemKey}{Environment.NewLine}";
}
}
However, I am getting an error in
txtItems.Text +=
$"{txtItems.Text}{item.ItemKey}{Environment.NewLine}";
The error says
Additional information: Cross-thread operation not valid: Control
'txtItems' accessed from a thread other than the thread it was created
on.
I checked in Debug and a new thread was created for GetCompletedItems(). When I read about Async and Await, I read that it doesn't necessarily create a new thread but it seems to have created a new one for some reason.
Is my implementation and understanding of Async and Await wrong?
Is it possible to use Async and Await in a Windows Forms application?
You cannot access UI thread on a different thread. This should help
private async void btnGetCompletedItems_Click(object sender, EventArgs e)
{
QueueSystem queueSystem = QueueSystem.NewInstance(75);
Stopwatch watch = new Stopwatch();
watch.Start();
var results = await Task.Run(() => queueSystem.GetCompletedItems());
foreach (var item in results)
{
txtItems.Text += $"{txtItems.Text}{item.ItemKey}{Environment.NewLine}";
}
watch.Stop();
lblTime.Text = $"{watch.ElapsedMilliseconds.ToString()} ms";
}
You can access the thread from another thread in a following way. It does helps to avoid the cross thread exception in your application.
private void Thread()
{
this.Invoke((System.Action)(() => {
//your thread call or definition
});
}
When I read about Async and Await, I read that it doesn't necessarily create a new
thread
This is true for regular async methods. Consider this:
private async void button1_Click(object sender, EventArgs e)
{
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
await DoesNothing();
}
private async Task DoesNothing()
{
// outputs the same thread id as similar line as from above;
// in particlar, for WinForms this means, that at this point
// we are still at UI thread
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1);
}
but it seems to have created a new one for some reason
This is what Task.Run is intended for:
Queues the specified work to run on the ThreadPool
In other words, it pushes anything you pass it as a delegate to a thread pool thread. Since we are in WinForms, this means, that anonymous method () => GetCompletedItems(queueSystem) will be executed at thread pool thread, not at UI one.
Here's code sample from above with little change:
private async void button1_Click(object sender, EventArgs e)
{
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Run(DoesNothing);
}
private async Task DoesNothing()
{
// outputs DIFFERENT thread id;
// in particlar, for WinForms this means, that at this point
// we are not at UI thread, and we CANNOT access controls directly
Trace.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1);
}
I am calling Task.Run(() => DoSomething()).Result which causes the UI to freeze and it happens because am using ".Result". I need Result because i want to return the value.
I don't want the Method StartSomething to be async because I don't want to await the method StartSomething. I want the await to happen at DoSomething().
So basically I need a asynchronous method to be called by a synchronous method, without freezing the UI. Plus I want to return the value from the async method to the top level that is on Button Click.
Can this code be improved or is there any other solution?
private TaskCompletionSource<bool> TaskCompletion = null;
private void Button_Click(object sender, RoutedEventArgs e)
{
bool k = StartSomething();
}
private bool StartSomething()
{
return Task.Run(() => DoSomething()).Result;
}
private async Task<bool> DoSomething()
{
TaskCompletion = new TaskCompletionSource<bool>();
await Task.WhenAny(TaskCompletion.Task, Task.Delay(3000));
MessageBox.Show("DoSomething");
return true;
}
Method StartSomething() doesn't make sense to me. It starts a new Task and then just synchronously waits for the result (.Result) of this task, which is effectively useless - it is nearly [*] the same as calling DoSomething() directly. Also DoSomething() is already asynchronous so you don't need to start a new Task for it.
It looks like you don't need StartSomething() method at all. If you make Button_Click handler async, you can then simply await DoSomething() directly:
private TaskCompletionSource<bool> TaskCompletion = null;
private async void Button_Click(object sender, RoutedEventArgs e)
{
bool k = await DoSomething();
}
private async Task<bool> DoSomething()
{
TaskCompletion = new TaskCompletionSource<bool>();
await Task.WhenAny(TaskCompletion.Task, Task.Delay(3000));
MessageBox.Show("DoSomething");
return true;
}
Edit:
While using async all the way down solution (as shown above) is IMO the preferred way, if you really can't change calling code to async, I can think of two ways to call async method from synchronous method without blocking UI. First is to manually set up a continuation tasks like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
DoSomething().ContinueWith((task) =>
{
bool k = task.Result;
// use the result
},
// TaskScheduler argument is needed only if the continuation task
// must run on the UI thread (eg. because it access UI elements).
// Otherwise this argument can be omitted.
TaskScheduler.FromCurrentSynchronizationContext());
// Method can exit before DoSomething().Result becomes
// available, which keep UI responsive
}
So you basicly split synchronous method (one split instead of each await) into several parts (continuation lambda methods) linked by .ContinueWith. This is similar to what await does under a hood. Problem is that unlike await (which produces nice and clean code), your code will be full of these continuation lambdas. And it will get much worse when you add exception handling blocks, using blocks, etc.
The second approach is using nested loops, eg. Stephen Toub's WaitWithNestedMessageLoop extension method:
static T WaitWithNestedMessageLoop<T>(this Task<T> task)
{
var nested = new DispatcherFrame();
task.ContinueWith(_ => nested.Continue = false, TaskScheduler.Default);
Dispatcher.PushFrame(nested);
return task.Result;
}
Nested loops are quite advanced technique (I actually never used it) and I don't recommend using it unless you have to.
[*] There are differences in exception handling, executing thread, etc., but these are not relevant to this question.
I'm buildind a synchronization tool that's working pretty well, but a noise problem's that I've an heavy method that freeze the UI.
Now, I know that I can solve this situation with Thread or Task, but in the Sync(); method I've a lot of access to the UI control.
Actually for access to MainWindow control I've created something like this:
public static MainWindow AppWindow;
public MainWindow()
{
InitializeComponent();
AppWindow = this;
}
so from any class I can simply do this: MainWindow.AppWindow.UIControlName. As you can imagine, if I use Task or Thread, this solution will become useless. 'cause I'll need to write this for each control:
MainWindow.AppWindow.UIControlName.Dispatcher.BeginInvoke(
(Action)(() => {
MainWindow.AppWindow.UIControlName.Content = "Synchronization in progress";
}));
Imagine that I have 20 or more of these lines, the code would become really ugly looking and long, for easy access to the UI control.
Now I wonder what is the best way to call a method asynchronously and return immediately to the caller without blocking the UI.
Without an asynchronous programming for this kind of applications the user experience is not really write home about.
You can either wrap all ugly stuff with dispatcher in separate methods and use those, or use async\await like this:
private async void ButtonClicked(object sender, RoutedEventArgs e) {
var result = await LongRunningOperation();
MainWindow.AppWindow.UIControlName.Content = "Synchronization in progress";
await YetAnotherLongRunningOperation();
// update again
}
Where LongRunningOperation is:
public async Task<SomeResult> LongRunningOperation() {
// do some stuff here
return new SomeResult();
}
or
public async Task LongRunningOperation() {
// do some stuff
}
You can also do it like this:
private async void ButtonClicked(object sender, RoutedEventArgs e) {
var result = await Task.Run(() => LongRunningOperation());
MainWindow.AppWindow.UIControlName.Content = "Synchronization in progress";
await YetAnotherLongRunningOperation();
// update again
}
That is because by default before await current synchronization context is captured, and after await this context is restored. In UI applications (like WPF or WinForms) that means if before await you were on UI thread - you will be there after await too, and as such can freely access UI controls.
You might ask - when should you declare your methods async and when just use Task.Run. If you do pure CPU computations - you can use Task.Run. If you do any IO (file access, network access, etc) - declare your method async and use async methods provided by IO-related classes (like FileStream.ReadAsync and such).
For example:
private async Task LongRunningOperation() {
string contents;
using (var fs = File.OpenRead("some file")) {
using (var reader = new StreamReader(fs)) {
contents = await reader.ReadToEndAsync();
}
}
var downloadedFile = await new WebClient().DownloadDataTaskAsync("some file url");
}
In CefSharp WinForms, I'm trying to get the html source of the page using JS once the page has loaded, however the application is freezing. I'm using a BackgroundWorker and the concerned functions are as follows:
void bw_DoWork(object sender, DoWorkEventArgs e)
{
browser.Load("http://www.google.com");
browser.FrameLoadEnd += delegate
{
object js = EvaluateScript(browser, "1+1");
MessageBox.Show(js.ToString());
};
}
object EvaluateScript(ChromiumWebBrowser b, string script)
{
var task = b.EvaluateScriptAsync(script);
task.Wait();
return task.Result;
}
As amaitland pointed out, FrameLoadEnd was causing the hang by running in the UI thread. The below code is working:
void bw_DoWork(object sender, DoWorkEventArgs e)
{
first.Load("http://www.google.com");
browser.FrameLoadEnd += delegate
{
Task task = new Task(() => {
object js = EvaluateScript(browser, "document.getElementsByTagName('html')[0].innerHTML;");
MessageBox.Show(js.ToString());
});
task.Start();
};
}
static object EvaluateScript(ChromiumWebBrowser b, string script)
{
var task = b.EvaluateScriptAsync(script);
task.Wait();
JavascriptResponse response = task.Result;
return response.Success ? (response.Result ?? "") : response.Message;
}
Whilst you assign FrameLoadEnd in the BackgroundWorker thread, it's actually executed on the underlying CEF UI thread, for which you cannot block without issues.
I'd typically suggest you spawn a Task from within the event handler to complete your work.
As a general rule, it's a bad idea to use Task.Wait on async code; rather, you should use async "all the way down". See also Don't Block on Async Code by Stephen Cleary. The short answer is that if you do this in an application with a synchronization context, you can cause a circular wait for the synchronization context (and hence a deadlock). The article I linked to has several examples of this, but I'd strongly suggest replacing Task.Wait with await here if possible.
This question already has answers here:
The calling thread cannot access this object because a different thread owns it
(15 answers)
Closed 2 years ago.
Is there a way to solve this error " The calling thread cannot access this object because a different thread owns it" without using dispatcher because dispatcher causes freezing on UI when the codes has a longer time to process is there another way to do it? without causing the freeze on the UI
No, you have to update the UIElement on the UI thread as the error says.
Yes, there other ways to run something on the UI thread other than using the Dispatcher, but they like the Dispatcher still run whatever it is you want to run on the UI thread - so will still freeze the UI.
If you are using C# 5 and .NET 4.5 or above you can easily run your long running process without blocking the UI Thread then when it completes continue on the UI thread (without worrying about how it works) using the async and await keywords:
private async Task<string> SimLongRunningProcessAsync()
{
await Task.Delay(2000);
return "Success";
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
button.Content = "Running...";
var result = await SimLongRunningProcessAsync();
button.Content = result;
}
If you do not have those however you will want to use the Dispatcher. The Dispatcher actually assists you running processes without freezing the UI
What you want to do is run the long running processes off the UI thread then when it is finished update the UI - which the Dispatcher helps you to:
Start long process on another thread and return immediately.
(long process still running, UI continues to update)
Long process finishes, update the UI on the UI thread.
e.g.:
private void UpdateButtonContent(string text)
{
button.Content = text;
}
private void SimLongRunningProcess()
{
Thread.Sleep(2000);
}
private void OnProcessFinished(Task task)
{
string content;
if(task.Exception != null)
{
content = task.Exception.Message;
}
else
{
content = "Success";
}
Dispatcher.BeginInvoke(new Action<string>(UpdateButtonContent), DispatcherPriority.Normal, content);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Start long running process and return immediatly
var task = Task.Factory.StartNew(SimLongRunningProcess);
task.ContinueWith(OnProcessFinished);
}
If you are using .NET 4.0 or newer, you can utilize the async and await keywords for clean, asynchronous code. This feature is built into 4.5 directly, and for 4.0 there is a NuGet package available from Microsoft (Microsoft.Bcl.Async) to enable this functionality.
For example, a user clicks a button and you wish to do something that may take a bit of time, then report back to the user.
// Notice how this method is marked 'async', this allows the 'await' keyword
async void OnButtonClicked(object sender, EventArgs e)
{
var button = sender as Button;
button.IsEnabled = false;
button.Text = "Calculating...";
int result = await DoSomeWork();
button.IsEnabled = true;
button.Text = "Calculate";
}
// This is an asynchronous method that returns an integer result
Task<int> DoSomeWork()
{
// Do some lengthy computation here, will be run on a background thread
return 42;
}
Alternatively, you could use other mechanisms like the BackgroundWorker class, or the Asynchronous Programming Model (APM) with callbacks. These are fine, however the async/await pattern is preferable.
If you have a choice, target .NET 4.5 (Win7+). If you must also support Windows XP, target .NET 4.0 and use the NuGet packages for Microsoft.Bcl.Async.