I am trying to implement a method called ReadAllLinesAsync using the async feature. I have produced the following code:
private static async Task<IEnumerable<string>> FileReadAllLinesAsync(string path)
{
using (var reader = new StreamReader(path))
{
while ((await reader.ReadLineAsync()) != null)
{
}
}
return null;
}
private static void Main()
{
Button buttonLoad = new Button { Text = "Load File" };
buttonLoad.Click += async delegate
{
await FileReadAllLinesAsync("test.txt"); //100mb file!
MessageBox.Show("Complete!");
};
Form mainForm = new Form();
mainForm.Controls.Add(buttonLoad);
Application.Run(mainForm);
}
I expect the listed code to run asynchronously and as a matter of fact, it does! But only when I run the code without the Visual Studio Debugger.
When I run the code with the Visual Studio Debugger attached, the code runs synchronously, blocking the main thread causing the UI to hang.
I have attempted and succeeded to reproduce the problem on three machines. Each test was conducted on a 64bit machine (either Windows 8 or Windows 7) using Visual Studio 2012.
I would like to know why this problem is occuring and how to solve it (as running without the debugger will likely hinder development).
The problem is that you are calling await reader.ReadLineAsync() in a tight loop that does nothing - except return execution to the UI thread after each await before starting all over again. Your UI thread is free to process windows events ONLY while ReadLineAsync() tries to read a line.
To fix this, you can change the call to await reader.ReadLineAsync().ConfigureAwait(false).
await waits for the completion of an asynchronous call and returns execution to the Syncrhonization context that called await in the first place. In a desktop application, this is the UI thread. This is a good thing because it allows you to update the UI directly but can cause blocking if you process the results of the asynchronous call right after the await.
You can change this behavior by specifying ConfigureAwait(false) in which case execution continues in a different thread, not the original Synchronization context.
Your original code would block even if it wasn't just a tight loop, as any code in the loop that processed the data would still execute in the UI thread. To process the data asynchronously without adding ConfigureAwait, you should process the data in a taks created using eg. Task.Factory.StartNew and await that task.
The following code will not block because processing is done in a different thread, allowing the UI thread to process events:
while ((line= await reader.ReadLineAsync()) != null)
{
await Task.Factory.StartNew(ln =>
{
var lower = (ln as string).ToLowerInvariant();
Console.WriteLine(lower);
},line);
}
I'm seeing the same problem as you to an extent - but only to an extent. For me, the UI is very jerky in the debugger, and occasionally jerky not in the debugger. (My file consists of lots of lines of 10 characters, by the way - the shape of the data will change behaviour here.) Often in the debugger it's good to start with, then bad for a long time, then it sometimes recovers.
I suspect the problem may simply be that your disk is too fast and your lines are too short. I know that sounds crazy, so let me explain...
When you use an await expression, that will only go through the "attach a continuation" path if it needs to. If the results are present already, the code just extracts the value and continues in the same thread.
That means, if ReadLineAsync always returns a task which is completed by the time it returns, you'll effectively see synchronous behaviour. It's entirely possible that ReadLineAsync looks at what data it's already got buffered, and tries to synchronously find a line within it to start with. The operating system may well then read more data from the disk so that it's ready for your application to use... which means that the UI thread never gets a chance to pump its normal messages, so the UI freezes.
I had expected that running the same code over a network would "fix" the problem, but it didn't seem to. (It changes exactly how the jerkiness is shown, mind you.) However, using:
await Task.Delay(1);
Does unfreeze the UI. (Task.Yield doesn't though, which again confuses me a lot. I suspect that may be a matter of prioritization between the continuation and other UI events.)
Now as for why you're only seeing this in the debugger - that still confuses me. Perhaps it's something to do with how interrupts are processed in the debugger, changing the timing subtly.
These are only guesses, but they're at least somewhat educated ones.
EDIT: Okay, I've worked out a way to indicate that it's at least partly to do with that. Change your method like this:
private static async Task<IEnumerable<string>>
FileReadAllLinesAsync(string path, Label label)
{
int completeCount = 0;
int incompleteCount = 0;
using (var reader = new StreamReader(path))
{
while (true)
{
var task = reader.ReadLineAsync();
if (task.IsCompleted)
{
completeCount++;
}
else
{
incompleteCount++;
}
if (await task == null)
{
break;
}
label.Text = string.Format("{0} / {1}",
completeCount,
incompleteCount);
}
}
return null;
}
... and create and add a suitable label to the UI. On my machine, both in debug and non-debug, I see far more "complete" hits than "incomplete" - oddly enough, the ratio of complete to incomplete is 84:1 consistently, both under the debugger and not. So it's only after reading about one in 85 lines that the UI can get a chance to update. You should try the same on your machine.
As another test, I added a counter incrementing in the label.Paint event - in the debugger it only executed 1/10th as many times as not in the debugger, for the same number of lines.
Visual Studio isn't actually executing the asynchronous callback synchronously. However, your code is structured in such a manner that it is "flooding" the UI thread with messages that you may not need to execute on a UI thread. Specifically, when FileReadAllLinesAsync resumes execution in the body of the while loop, it does so on the SynchronizationContext that was captured on the await line in the same method. What this means is for every line in your file, a message is posted back to the UI thread to execute 1 copy of the body of that while loop.
You can resolve this issue by using ConfigureAwait(false) carefully.
In FileReadAllLinesAsync, the body of the while loop is not sensitive to which thread it runs on, so you can use the following instead:
while ((await reader.ReadLineAsync().ConfigureAwait(false)) != null)
In Main, suppose you do want the MessageBox.Show line to execute on the UI thread (perhaps you also have a buttonLoad.Enabled = true statement there). You can (and will!) still get this behavior without any changes to Main, since you did not use ConfigureAwait(false) there.
I suspect the delays you observe in the debugger are due to .NET's slower performance in managed/unmanaged code while a debugger is attached, so dispatching each of those millions of messages to the UI thread is up to 100x slower when you have the debugger attached. Rather than try to speed up that dispatching by disabling features, I suspect item #1 above will resolve the bulk of your problems immediately.
From Task-based Asynchronous Pattern in Microsoft Download Center :
For performance reasons, if a task has already completed by the time
the task is awaited, control will not be yielded, and the function
will instead continue executing.
And
In some cases, the amount of work required to complete the operation
is less than the amount of work it would take to launch the operation
asynchronously (e.g. reading from a stream where the read can be
satisfied by data already buffered in memory). In such cases, the
operation may complete synchronously, returning a Task that has
already been completed.
So my last answer was incorrect (short-timing asynchronous operation is synchronous for performance reasons).
Related
I want to implement a file copying process asynchronously in C# using async/await/Task<T>. The process should be non-blocking for the UI, so will be run in a separate Task. There are situations though, when the process needs to be paused and synchronous action must be performed.
For instance, it may happen, that a file, which is being copied, already exists in the target location. In this case, a modal dialog should appear, asking user what to do. The dialog should be modal in respect to the window, which shows progress of copying, and since showing it is a UI operation, it should be shown from the main thread. Moreover, if multiple copying tasks encounter the same situation, they should be handled one-by-one, not all at the same time.
What is the proper way of "synchronously pausing" a running task?
My only idea looks like following:
Task keeps its whole state in a class instance
When such situation happens, it terminates, returning a class containing:
Information on what happened
State instance
This finishes the await call and caller can synchronously react to whatever happened in the Task.
When user decides to continue process (e.g. replace the target file or rename copied one), the Task is re-executed with the state returned from the previous execution along with user's decision.
The pseudocode for this solution would look like following:
public async Task ExecuteProcess()
{
UserDecision lastDecision = null;
var state = new();
bool finished = false;
while (!finished)
{
var result = await DoExecuteProcess(state, lastDecision);
if (result is UserChoiceResult)
{
lastDecision = AskUser();
}
else if (result is FinishedResult)
{
finished = true;
}
else
throw new InvalidOperationException("Unsupported async task result");
}
}
I'm wondering though, if there is a better solution for this problem, as this one seems a little bit sketchy for me (returning a "partially-done-requiring-more-information" result from async task).
I'm having trouble understanding what runs on the main thread during an async await operation and would be grateful for some answers.
Let's say I have a button that is supposed to log the user in.
it is supposed to block all other user input while the login process transpires, show a progress view and then when the result comes in display it
and here is the method that performs the log in
button_clicked(object sender, EventArgs e) {
do_login(); //I do not await the result
do_some_other_stuff(); //this doesn't actually exist I just put it here to ask my questions
}
async Task do_login() {
string user_name = txtUser.Text;
string password = txtPassword.Text;
show_progress(true); //this is not an async method;
string error = await _login.do_login(user_name, password);//this is an async method that can take up to 20 seconds to complete;
show_progress(false);
if (error != null) {
show_error(error);
} else {
show_next_screen();
}
}
I have two questions on the above example
a) What will be run on the main thread?
If I understand it correctly only _login.do_login will be run on a seperate thread, all others will be on the main thread, is this correct?
b) In what order will the methods be executed?
Again if I understand it correctly, it will be :
do_login()
show_progress(true);
_login.do_login starts;
do_some_other_stuff();
_login.do_login finishes;
show_progress(false);
and it will continue from there
is this correct? if not, how can I achieve such a behaviour?
c) If my code above is correct then why do I keep receiving a warning that do_login() is not awaited? I do not wish to await it I just want it to run what it can and return when it wants, should I ignore that warning?
Technically, depending on the implementation of do_login, everything could run in the main thread. In this case I assume you're contacting a web server, so that part won't, but this is not always true. And asynchronous operation does not necessarily executes in another thread. One operation is asynchronous when:
It doesn't block the calling thread.
Usually, UI threads run an 'event loop'. So an asynchronous task could simply put a new piece of work into the event queue to be executed whenever the scheduler determines, but in the same thread. In this case you don't use two threads, but still, you don't have to wait for the task to complete and you don't know when it'll finish.
To be precise, all the code in your post will run in the main thread. Only the part in do_login that manages the connection with the server, waiting and retrieving data will execute asynchronously.
You're mostly right about the sequence, with a few adjustments:
do_login() (until the await)
login._do_login() starts executing
do_some_other_stuff()
...
login.do_login finishes
show_progress()
The answer to your main question is: it depends. The _login.do_login method will likely be put onto its own thread, but it actually depends on the .NET task scheduler. In WPF and ASP.NET it will be scheduled onto the thread pool if it doesn't immediately return a completed task.
The important part is that you know it will not block execution of the calling (in your case, the main) thread. Your understanding of the method flow is correct since you don't await do_login.
As far as the warning goes; you can mark do_login as async void to avoid it, though generally you only do that for event handlers which can then await a Task returning method. If you do go the async void route; make sure to put a try/catch in as such methods will throw all the way up to the root handler and can cause your app to crash.
I have an application that works but after a while when I debug on my iPhone it hangs the phone and the only way I can recover is a hard reset of the button on the side and the home button.
First of all, could that be because my application has a memory leak?
Here's the code for the application. In particular, I am looking at the BeginInvokeOnMainThread method. Can someone tell me if they can see if there could be any problems with the way that it is implemented? Also, what's the purpose of the .ContinueWith((arg).
namespace Japanese
{
public partial class PhrasesFrame : Frame
{
CancellationTokenSource cts = new CancellationTokenSource();
public PhrasesFrame(PhrasesPage phrasesPage)
{
InitializeComponent();
this.phrasesPage = phrasesPage;
AS.phrasesFrame = this;
Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token).ContinueWith((arg) => { }));
}
public void Disappearing()
{
cts.Cancel();
}
public async Task ShowCards(CancellationToken ct)
{
AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories();
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
}
}
ContinueWith
First, let's address your question about .ContinueWith((arg) => { })). ContinueWith tells more code to execute once the original Task has completed. In our case, the code inside of ContinueWith will run once Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token) has finished.
In this case, there is no code inside of ContinueWith, so we can remove it.
Freezing
Yes, I can see that this code has potential to freeze the UI.
BeginInvokeOnMainThread will queue an Action to run on the Main Thread (also known as the UI Thread). The Main Thread is constantly listening for user input (tapping a button on the screen, pinch-to-zoom, etc.), and if this thread is busy doing a long-running task, it will not be able to respond to a user's input until it has finished; thus your app will appear frozen.
The code await Task.Delay(500); is being called by the Main Thread. We are thus telling the Main Thread to freeze itself for 500 milliseconds, and looping that indefinitely.
One solution would be to wrap this code in Task.Run which would put it in a background-thread and free the Main Thread to listen/respond to user input.
Task.Run(async () =>
{
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
More Threading Recommendations
Only use BeginInvokeOnMainThread when you need to update the UI. 99% of code can run on a background thread with no problems. The 1%, however, is code that updates the UI; any code that updates the UI must be run on the Main Thread.
If a task that takes longer than the refresh rate of the screen to execute, perform it on a background thread. For example, if the screen's refresh rate is 60Hz, it is updating 60-times per second, every 16.7ms. So if we have a block of code that takes 20ms to execute, we need to execute it on a background thread to ensure that we don't freeze the app and drop any frames.
The code above looks like it is accessing a database, which I would highly recommend moving to a background thread like so
await Task.Run(() => AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories());
First, if you are concerned about a memory leak, you can check for low-memory warnings in the device logs (accessible through XCode), or override the ReceiveMemoryWarning method in your app delegate to log an error.
Secondly, there's nothing obviously wrong with the way you're calling BeginInvokeOnMainThread that would cause a leak. The ContinueWith is a no-op that doesn't affect the operation of the code - I'm guessing it's there to avoid a compiler warning that you're not awaiting the task.
Thirdly, if you suspect that this code is causing a leak, you should use logging and/or breakpoints to confirm that it's behaving as expected. Is the task correctly cancelled when you navigate away from the page? Do you see multiple instances of of the ShowCards task running? If this code turns out to be behaving correctly, then the source of the hang lies elsewhere in your app. For instance, it looks like you're making a database call twice a second - maybe it's not cleaning up resources properly.
I'm making an Visual Studio adornment extension. I want to update adornments if there is no user input at least 2 seconds. So i constructed a worker and tried to remove and add adornment but VS says it can't be updated because non-ui thread had called it. So I waited without thread then my editor goes really laggy (because the ui thread waits)
I want to know if there is a way to update adornments with lazy update.
Drawing adornment is done by calling AddAdornment(), and i can't find how to invoke ui thread to draw.
Below is my code
internal async void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
Print("OnLayoutChanged Called");
task = Task.Factory.StartNew(() =>
{
Print("task Started");
if (e.NewSnapshot != e.OldSnapshot)
{
parseStopwatch.Restart();
shouldParse = true;
}
ParseWork(e);
});
await task;
}
private async void ParseWork(object param)
{
var e = (TextViewLayoutChangedEventArgs)param;
if (e == null)
{
shouldParse = false;
parseStopwatch.Stop();
CsharpRegionParser.ParseCs(this.view.TextSnapshot);
DrawRegionBox();
return;
}
while (shouldParse)
{
Task.Delay(10);
if ((shouldParse && parseStopwatch.ElapsedMilliseconds > 2000) || parseStopwatch.ElapsedMilliseconds > 5000)
{
break;
}
}
shouldParse = false;
parseStopwatch.Stop();
CsharpRegionParser.ParseCs(this.view.TextSnapshot);
DrawRequest(e);
return;
}
I'm not sure why you were down-voted, particularly because this is an interesting problem when dealing with extensions.
So, to your first problem: Visual Studio has the same requirements as WPF (with some added complications due to its COM dependency). You can't update a UI element when you're not on the Main (UI) thread. Unfortunately, if you dive right in and approach it using the strategies you'd use for WPF, you'll experience a whole other world of problems (deadlocks, mostly).
First things first, brush up on how to handle switching from background to UI threads in Visual Studio extension land. I found Asynchronous and Multithreaded programming within VS using JoinableTaskFactory to be helpful in explaining.
I had to do something similar with an expensive parsing operation. It was pretty straight forward.
My parser executes as part of an IViewModelTagger instance and uses the following sequence (roughly):
It subscribes to the ITextBuffer.ChangedLowPriority event with an async void event handler.
Immediately on fire, it cancels any parsing operation in progress via a CancellationToken.Cancel() call. The cancellation token is passed into everything that supports it (in Roslyn, it's supported everywhere you would want it to be).
It begins the parsing operation, but before starting it, I have a Task.Delay(200, m_cancellationToken) call. I 200ms based on my typing speed and the fact that Roslyn's operations have CancellationToken overloads for anything expensive (my parsing work is pretty light-weight, too). YMMV.
I work with WPF components that require the UI thread quite a bit and they're intermingled within the IViewModelTagger and the IWpfTextViewListener. They're lightweight enough that I could have skipped async'ing them, but on very large classes they can hang the UI.
To handle this, I did the following:
On the TextViewLayoutChanged, I subscribe with an async void event handler.
I Task.Run() the expensive operations first, preventing the UI from being blocked.
When I do the final creation of the WPF UI elements and add them as adornments finalization (along with a couple of operations within the SDK that require it), I await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync() to get the UI thread.
I mentioned "other SDK operations", that's important. There are several things you cannot do within the SDK on anything but the Main thread (memory is failing me now, but parts of the TextView in particular will fail, and not consistently, if they're accessed on background threads).
There are more options for executing the work off of the UI thread (Ordinary Task.Run works, as well as ThreadHelper.JoinableTaskFactory.Run). The Andrew Arnott post linked earlier in my answer explains all of the choices. You'll want to understand that fully since there are reasons to use some over others depending on the task.
Hope that helps!
Task.Delay as used in your code returns a task that completes when you delay. If you call it like that and ignore the result, it didn't do what you thought it did. What you probably meant to is instead of calling Task.Factory.StartNew as you did, you want:
var cancellationTokenSource = new CancellationTokenSource();
Task.Delay(2000, cancellationTokenSource.Token).ContinueWith(() => DoWork(), cancellationTokenSource.Token, TaskScheduler.Current).
This says effectively "kick off a timer that'll wait 2 seconds, and then once it completes run the DoWork method on the UI thread. If more typing happens, then you can call cancellationTokenSource.Cancel() and just run again.
Also, I do have to ask about your type "CSharpRegionParser". If you need region information and you're on Visual Studio 2015, then you can get the syntax tree from Roslyn and you should be watching workspace change events rather than hooking LayoutChanged. You're also best off then structuring your system as a tagger/adornment manager pair as it might be clearer to write...it's not clear to me why you'd do parsing logic in LayoutChanged since LayoutChanged is something that happens during visual layout, including scrolling, resizing, etc.
I know there are a lot of questions about async/await, but I couldn't find any answer to this.
I've encountered something I don't understand, consider the following code:
void Main()
{
Poetry();
while (true)
{
Console.WriteLine("Outside, within Main.");
Thread.Sleep(200);
}
}
async void Poetry()
{
//.. stuff happens before await
await Task.Delay(10);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Inside, after await.");
Thread.Sleep(200);
}
}
Obviously, on the await operator, the control returns to the caller, while the method being awaited, is running on the background. (assume an IO operation)
But after the control comes back to the await operator, the execution becomes parallel, instead of (my expectation) remaining single-threaded.
I'd expect that after "Delay" has been finished the thread will be forced back into the Poetry method, continues from where it left.
Which it does. The weird thing for me, is why the "Main" method keeps running? is that one thread jumping from one to the other? or are there two parallel threads?
Isn't it a thread-safety problem, once again?
I find this confusing. I'm not an expert. Thanks.
I have a description on my blog of how async methods resume after an await. In essence, await captures the current SynchronizationContext unless it is null in which case it captures the current TaskScheduler. That "context" is then used to schedule the remainder of the method.
Since you're executing a Console app, there is no SynchronizationContext, and the default TaskScheduler is captured to execute the remainder of the async method. That context queues the async method to the thread pool. It is not possible to return to the main thread of a Console app unless you actually give it a main loop with a SynchronizationContext (or TaskScheduler) that queues to that main loop.
Read It's All About the SynchronizationContext and I'm sure it'll become less confusing. The behavior you're seeing makes perfect sense. Task.Delay uses Win32 Kernel Timer APIs internally (namely, CreateTimerQueueTimer). The timer callback is invoked on a pool thread, different from your Main thread. That's where the rest of Poetry after await continues executing. This is how the default task scheduler works, in the absence of synchronization context on the original thread which initiated the await.
Because you don't do await the Poetry() task (and you can't unless you return Task instead of void), its for loop continues executing in parallel with the while loop in your Main. Why, and more importantly, how would you expect it to be "forced" back onto the Main thread? There has to be some explicit point of synchronization for this to happen, the thread cannot simply get interrupted in the middle of the while loop.
In a UI application, the core message loop may serve as such kind of synchronization point. E.g. for a WinForms app, WindowsFormsSynchronizationContext would make this happen. If await Task.Delay() is called on the main UI thread, the code after await would asynchronously continue on the main UI thread, upon some future iteration of the message loop run by Application.Run.
So, if it was a UI thread, the rest of the Poetry wouldn't get executed in parallel with the while loop following the Poetry() call. Rather, it would be executed when the control flow had returned to the message loop. Or, you might explicitly pump messages with Application.DoEvents() for the continuation to happen, although I wouldn't recommend doing that.
On a side note, don't use async void, rather use async Task, more info.
When you call an async routine the purpose of this is to allow the program to run a method while still allowing the calling routine, form or application to continue to respond to user input (in other words, continue execution normally). The "await" keyword pauses execution at the point it is used, runs the task using another thread then returns to that line when the thread completes.
So, in your case if you want the main routine to pause until the "Poetry" routine is done you need to use the await keyword something like this:
void async Main()
{
await Poetry();
while (true)
{
Console.WriteLine("Outside, within Main.");
Thread.Sleep(200);
}
}
You will also need to change the definition for Poetry to allow the await keyword to be used:
async Task Poetry()
Because this question really intrigued me I went ahead and wrote an example program you can actually compile. Just create a new console application and paste this example in. You can see the result of using "await" versus not using it.
class Program
{
static void Main(string[] args)
{
RunMain();
// pause long enough for all async routines to complete (10 minutes)
System.Threading.Thread.Sleep(10 * 60 * 1000);
}
private static async void RunMain()
{
// with await this will pause for poetry
await Poetry();
// without await this just runs
// Poetry();
for (int main = 0; main < 25; main++)
{
System.Threading.Thread.Sleep(10);
Console.WriteLine("MAIN [" + main + "]");
}
}
private static async Task Poetry()
{
await Task.Delay(10);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("IN THE POETRY ROUTINE [" + i + "]");
System.Threading.Thread.Sleep(10);
}
}
}
Happy testing! Oh, and you can still read more information here.
I'd like to answer my own question here.
Some of you gave me great answers which all helped me understand better (and were thumbed up). Possibly no one gave me a full answer because I've failed to ask the full question. In any case someone will encounter my exact misunderstanding, I'd like this to be the first answer (but I'll recommend to look at some more answers below).
So, Task.Delay uses a Timer which uses the operating system to fire an event after N milliseconds. after this period a new pooled thread is created, which basically does almost nothing.
The await keyword means that after the thread has finished (and it's doing almost nothing) it should continue to whatever comes after the await keyword.
Here comes the synchronization context, as mentioned in other answers.
If there is no such context, the same newly-created-pooled-thread will continue running what ever comes after the await.
If there is a synchronizing context, the newly-created-pool-thread, will only push whatever comes after the await, into synchronizing context.
For the sake of it, here are a few points I didn't realize:
The async/await are not doing anything which wasn't (technologly speaking) possible before. Just maybe amazingly clumsy.
It's is just a language support for some of .NET 4.5 classes.
It's much like yield return. It may break your method into a few methods, and may even generate a class behind, and use some methods from the BCL, but nothing more.
Anyway, I recommend reading C# 5.0 In A Nutshell's chapter "Concurrency and Asynchrony". It helped me a lot. It is great, and actually explains the whole story.