class Laziness
{
static string cmdText = null;
static SqlConnection conn = null;
Lazy<Task<Person>> person =
new Lazy<Task<Person>>(async () =>
{
using (var cmd = new SqlCommand(cmdText, conn))
using (var reader = await cmd.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
string firstName = reader["first_name"].ToString();
string lastName = reader["last_name"].ToString();
return new Person(firstName, lastName);
}
}
throw new Exception("Failed to fetch Person");
});
public async Task<Person> FetchPerson()
{
return await person.Value;
}
}
And the book, "Concurrency in .NET" by Riccardo Terrell, June 2018, says:
But there's a subtle risk. Because Lambda expression is asynchronous,
it can be executed on any thread that calls Value and the expression
will run within the context. A better solution is to wrap the
expression in an underlying Task which will force the asynchronous
execution on a thread pool thread.
I don't see what's the risk from the current code ?
Is it to prevent deadlock in case the code is run on the UI thread and is explicity waited like that:
new Laziness().FetchPerson().Wait();
I don't see what's the risk from the current code ?
To me, the primary issue is that the asynchronous initialization delegate doesn't know what context/thread it'll run on, and that the context/thread could be different based on a race condition. For example, if a UI thread and a thread pool thread both attempt to access Value at the same time, in some executions the delegate will be run in a UI context and in others it will be run in a thread pool context. In the ASP.NET (pre-Core) world, it can get a bit trickier: it's possible for the delegate to capture a request context for a request that is then canceled (and disposed), and attempt to resume on that context, which isn't pretty.
Most of the time, it wouldn't matter. But there are these cases where Bad Things can happen. Introducing a Task.Run just removes this uncertainty: the delegate will always run without a context on a thread pool thread.
I simplified your example to show what happens in each case. In the first case the Task is created using an async lambda:
Lazy<Task<string>> myLazy = new Lazy<Task<string>>(async () =>
{
string result = $"Before Delay: #{Thread.CurrentThread.ManagedThreadId}";
await Task.Delay(100);
return result += $", After Delay: #{Thread.CurrentThread.ManagedThreadId}";
});
private async void Button1_Click(object sender, EventArgs e)
{
int t1 = Thread.CurrentThread.ManagedThreadId;
var result = await myLazy.Value;
int t2 = Thread.CurrentThread.ManagedThreadId;
MessageBox.Show($"Before await: #{t1}, {result}, After await: #{t2}");
}
I embedded this code in a new Windows Forms application with a single button, and on clicking the button this message popped up:
Before await: #1, Before Delay: #1, After Delay: #1, After await: #1
Then I changed the valueFactory argument to use Task.Run instead:
Lazy<Task<string>> myLazy = new Lazy<Task<string>>(() => Task.Run(async () =>
{
string result = $"Before Delay: #{Thread.CurrentThread.ManagedThreadId}";
await Task.Delay(100);
return result += $", After Delay: #{Thread.CurrentThread.ManagedThreadId}";
}));
Now the message is this:
Before await: #1, Before Delay: #3, After Delay: #4, After await: #1
So not using Task.Run means that your code before, between and after the awaits will run on the UI thread. Which might not be a big deal, unless there is CPU intensive or IO blocking code hidden somewhere. For example the constructor of the Person class, as innocent as it might look, could contain some call to a database or web API. By using Task.Run you can be sure that the initialization of the Lazy class will not touch the UI thread before it's done.
Related
I recently came across some code which confused me heavily, I have always thought that you must use threads or Async tasks, not mix and match between them,
public async Task DoWork()
{
Task.Delay(1000);
}
Now I saw code calling this like so:
public void Main()
{
var thread = new Thread(async () => { await DoWorkAync(); })
{
Priority = ThreadPriority.Highest,
IsBackground = true
};
// Start thread
proccessThread.Start();
}
Now this magically seemed to NOT create a thread each time it was run, it seemed to be using the ThreadPool.
now what I am struggling to understand is the difference between the above and:
public void Main()
{
var task = Task.Run(DoWorkASync);
}
From my testing, it seems that C# Thread has a different functionality when passing in an Async Expression vs the standard method on which to run>
This construct:
var thread = new Thread(async () => { await DoWorkAync(); });
// Start thread
proccessThread.Start();
Calls Thread constructor overload accepting ThreadStart delegate, and ThreadStart delegate is () => void. So you have this:
var thread = new Thread(StuffYourThreadExecutes);
thread.Start();
static async void StuffYourThreadExecutes() {
await DoWorkAsync();
}
So you start new thread and it runs the code until first asynchronous operation begins. Then thread exists. After that first asynchronous operation completes - the rest executes on whatever thread task scheduler providers (usually thread pool thread). Any exceptions which happen during this process cannot be observed.
For example if DoWorkAsync is something like:
static async Task DoWorkAsync(){
await Task.Delay(1000);
}
Then thread starts and almost immediately exits, doing nothing useful.
Task.Run, when passing async delegate there, does what is stated in docs:
Queues the specified work to run on the thread pool and returns a
proxy for the task
So whole operation just runs on thread pool thread without creating threads for nothing. You can observe exceptions by awaiting task returned by Task.Run.
Related to this question: Does await completely blocks the thread?
[...] it will first check to see if the called method completed, and if not will register the continuation and return from that method call. Later, once that method completes, it will re-enter the state-machine in order to complete the method
And to this question also: When is the best place to use Task.Result instead of awaiting Task
await simply means "this workflow cannot progress further until this task is completed, so if it is not complete, find more work to do and come back later"
And finally to this post: https://blog.stephencleary.com/2012/02/async-and-await.html
If “await” sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method. Later on, when the awaitable completes, it will execute the remainder of the async method. If you’re awaiting a built-in awaitable (such as a task), then the remainder of the async method will execute on a “context” that was captured before the “await” returned.
So from these posts I get that the await operator does indeed not block, but when I've tried to test it i just cannot get this principle to work the way it states to work. Obviously I'm missing something:
//This will take 10 seconds
[HttpGet("test1")]
public async Task<TimeSpan> test()
{
var t1 = DateTime.Now;
var wait1 = DoAsyncEcho("The first!", 10000);
var wait2 = DoAsyncEcho("The second!", 10000);
_logger.LogInformation(await wait1);
_logger.LogInformation(await wait2);
_logger.LogInformation("DONE!");
var t2 = DateTime.Now;
return t2 - t1;
}
//This will take 10 seconds too
[HttpGet("test2")]
public async Task<TimeSpan> test2()
{
var t1 = DateTime.Now;
var wait1 = DoAsyncEcho("The first!", 10000);
var wait2 = DoAsyncEcho("The second!", 10000);
Thread.Sleep(10000);
_logger.LogInformation(await wait1);
_logger.LogInformation(await wait2);
_logger.LogInformation("DONE!");
var t2 = DateTime.Now;
return t2 - t1;
}
//This will take 20
[HttpGet("test3")]
public async Task<TimeSpan> test3()
{
var t1 = DateTime.Now;
var wait1 = await DoAsyncEcho("The first!", 10000);
var wait2 = await DoAsyncEcho("The second!", 10000);
_logger.LogInformation(wait1);
_logger.LogInformation(wait2);
_logger.LogInformation("DONE!");
var t2 = DateTime.Now;
return t2 - t1;
}
//This will take 30
[HttpGet("test4")]
public async Task<TimeSpan> test4()
{
var t1 = DateTime.Now;
var wait1 = await DoAsyncEcho("The first!", 10000);
var wait2 = await DoAsyncEcho("The second!", 10000);
Thread.Sleep(10000);
_logger.LogInformation(wait1);
_logger.LogInformation(wait2);
_logger.LogInformation("DONE!");
var t2 = DateTime.Now;
return t2 - t1;
}
private Task<string> DoAsyncEcho(string v, int t)
{
return Task<string>.Factory.StartNew(() =>
{
Thread.Sleep(t);
return v;
}
);
}
As I see from the methods test3 and test4, await does indeed wait, it does not enter into a state-machine and does a callback later on because it waits the full 10 seconds of the first DoAsyncEcho and then another 10s on the second call. On the methods test1 and test2 execution time lasts for 10s as code does not waits for the return of the DoAsyncEcho but only it awaits for the result later. Particulary test2 method sleeps the 3 calls of 10 seconds in parallel so after all it's just a 10s run.
What do I'm missing here?
I think the best way to demonstrate this is through a simple Windows Forms app.
Create a default Windows Forms app and drop 3 buttons onto it (called button1, button2 and button3.
Then add the following code:
async void button1_Click(object sender, EventArgs e)
{
this.Text = "[button1_Click] About to await slowMethodAsync()";
int result = await slowMethodAsync();
this.Text = "[button1_Click] slowMethodAsync() returned " + result;
}
void button2_Click(object sender, EventArgs e)
{
this.Text = "[button2_Click] About to start task to call slowMethod()";
int result = 0;
Task.Run(() =>
{
result = slowMethod();
}).ContinueWith(_ =>
{
this.Invoke(new Action(() =>
{
this.Text = "[button2_Click] slowMethod() returned " + result;
}));
});
}
void button3_Click(object sender, EventArgs e)
{
this.Text = "[button3_Click] About to call slowMethod()";
int result = slowMethod();
this.Text = "[button3_Click] slowMethod() returned " + result;
}
static async Task<int> slowMethodAsync()
{
await Task.Delay(5000);
return 42;
}
static int slowMethod()
{
Thread.Sleep(5000);
return 42;
}
If you try this code out, you will notice the following:
Pressing button1 will immediately change the title to [button1_Click] About to await Task.Delay(5000), and you can resize the dialog while waiting for 5 seconds, after which the title will change to [button1_Click] Awaited Task.Delay(5000).
The code for handling button2 is very roughly equivalent to the state machine that is generated from the await code for button1. If you press button2, you will see similar effects to pressing button1.
(The actual code for await is in reality quite different, but the underlying mechanism of using a continuation - i.e., ContinueWith() and Invoke(), to continue executing the code after the await on the UI thread illustrates its approach.)
The code for button3 completely blocks during the Thread.Sleep(), and if you press button3 the UI locks up completely for 5 seconds,.
To illustrate what happens with a non-UI example, consider the following console application:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
static class Program
{
static async Task Main()
{
Console.WriteLine("Main thread ID = " + Thread.CurrentThread.ManagedThreadId);
int result = slowMethod();
Console.WriteLine("result = " + result);
Console.WriteLine("After calling slowMethod(), thread ID = " + Thread.CurrentThread.ManagedThreadId);
result = await slowMethodAsync();
Console.WriteLine("result = " + result);
Console.WriteLine("After calling slowMethodAsync(), thread ID = " + Thread.CurrentThread.ManagedThreadId);
}
static async Task<int> slowMethodAsync()
{
await Task.Delay(5000);
return 42;
}
static int slowMethod()
{
Thread.Sleep(5000);
return 42;
}
}
}
If you run that, you will see output similar to the following:
Main thread ID = 1
result = 42
After calling slowMethod(), thread ID = 1
result = 42
After calling slowMethodAsync(), thread ID = 4
Note how the code has resumed on a different thread after the await.
The key thing to realise is that as far as calling code is concerned, y = await X(); does not return until it has a value to return, and the code that runs afterwards may be running on a different thread.
The effect of this in terms of blocking THREADS is that the calling thread is freed up to go off and execute some other code, and another thread is only required when the async method returns.
In many cases, this means that no additional thread is required (for the continuation), and in all cases it means that the original calling thread is not blocked and can be freed up to the thread pool for use for another task.
This is the "non blocking" part of all this.
For a good, detailed explanation of why sometimes no additional thread is needed, read Stephen Cleary's excellent "There is no thread".
It seems that you are confusing two different interpretations of wait and block. The objective of asynchronous code is to block your code, while the thread remains unblocked. If you don't want to block your code, then the solution is easy: don't use await. But if you don't block your code, then you can't use the result of the asynchronous operation, because the asynchronous operation is running concurrently with your code.
What has not happened yet belongs to the future, and the future is unknown. Not only do you not know the result, you don't even know if the operation succeeded or failed. In most cases this is problematic. You need the result of the operation before continuing with processing this result. So you must block your code. And this is why await was invented, to block your code without having to block a thread too.
You need the thread to remain unblocked, so that it continues running the UI message pump that keeps your application responsive. Just because your code is blocked, your _application) need not to be blocked also. For ASP.NET applications, you need the thread to remain unblocked so that it can serve other incoming web requests. The fewer threads you block, the more requests you can serve. In this case async/await becomes a booster of scalability.
I have an async codeblock running on the pageload.
The codes run smoothy until you reach capturevalue method where we create a new task.On executing that code block the await just freezes and then the control doesnt come back seems like the code just went to deadlock
protected void Page_Load(object sender, EventArgs e)
{
try
{
var textvalue = GetTextValueFromTask();
txtbox.Text = textvalue.Result;
string ss = "";
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private async Task<string> GetTextValueFromTask()
{
string strReturn = await CaptureValue();
return strReturn;
}
private async Task<string> CaptureValue()
{
Thread.Sleep(5000);
Task<string> T = Task.Factory.StartNew<string>(() => "hi");
return await T;
}
Then I made a small change in Capturevalue method.
private async Task<string> CaptureValue()
{
Thread.Sleep(5000);
Task<string> T = Task.Factory.StartNew<string>(() => "hi");
string ss = T.Result;
return await T;
}
Once I made that change it started working normal.What difference did it make on just fetching the result initially. Please help me Iam a newbee to async
The difference is that second time it doesn't happen any "await" because you waited the task yourself, so await doesn't do anything.
I think you missed the await keyword the first time, here:
var textvalue = await GetTextValueFromTask();
Without it your method GetTextValueFromTask runs synchronously, then it comes into CaptureValue method where await occurs. But the default behaviour of the await is that it tries to capture synchronization context where it was called and to continue the rest of the method in that context, in your example it is WPF synchronization context, which does not allow more than one thread to execute at once. But the continuation cannot proceed, because context is already used by await mechanism.
So, one more time. There is one thread (UI thread), that executes your code up to the last await, which is return await T;, then it yields back to the caller - GetTextValueFromTask, and again to the Page_Load when it gets blocked, because initially you called GetTextValueFromTask synchronously (without await). After that, your operation T completes, and your code tries to continue executing using the initial synchronization context, the WPF one. But it can't, because it is already waiting in the Page_Load.
The link in the comments describes the situation in more detail.
Also consider not using Thread.Sleep in async/await scenarios, because it kills all the "asynchronous" nature of the code. Further reading: link.
Another general piece of advice, which is not directly applicable to your source code, is not to use Task.Factory.StartNew, but rather use Task.Run. Explanation here.
Please use Task.Run() instead of Task.Factory.StartNew()
var T = Task.Run(() => "hi");
It's up to Task.Run to decide how to handle this task.
Also please use .ConfigureAwait(false) in your await calls that do not requires the continuation being done in the awaiter thread context.
I'm still learning the async/await, so please excuse me if I'm asking something obvious. Consider the following example:
class Program {
static void Main(string[] args) {
var result = FooAsync().Result;
Console.WriteLine(result);
}
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = await t2;
return result1 + result2;
}
static Task<int> Method1Async() {
return Task.Run(
() => {
Thread.Sleep(1000);
return 11;
}
);
}
static Task<int> Method2Async() {
return Task.Run(
() => {
Thread.Sleep(1000);
return 22;
}
);
}
}
This behaves as expected and prints "33" in the console.
If I replace the second await with an explicit wait...
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = t2.Result;
return result1 + result2;
}
...I seem to get the same behavior.
Are these two examples completely equivalent?
And if they are equivalent in this case, are there any other cases where replacing the last await by an explicit wait would make a difference?
Your replacement version blocks the calling thread waiting for the task to finish. It's hard to see a visible difference in a console app like that since you're intentionally blocking in Main, but they're definitely not equivalent.
They are not equivalent.
Task.Result blocks until the result is available. As I explain on my blog, this can cause deadlocks if you have an async context that requires exclusive access (e.g., a UI or ASP.NET app).
Also, Task.Result will wrap any exceptions in AggregateException, so error handling is harder if you synchronously block.
OK, I think I figured this out so let me sum it up, in what will hopefully be a more complete explanation than the answers provided so far...
Short Answer
Replacing the second await with an explicit wait will have no appreciable effect on a console application, but will block the UI thread of a WPF or WinForms application for the duration of the wait.
Also, the exception handling is slightly different (as noted by Stephen Cleary).
Long Answer
In a nutshell, the await does this:
If the awaited task has already finished, it just retrieves its result and continues.
If it hasn't, it posts the continuation (the rest of the method after the await) to the current synchronization context, if there is one. Essentially, await is trying to return us where we started from.
If there isn't a current context, it just uses the original TaskScheduler, which is usually thread pool.
The second (and third and so on...) await does the same.
Since the console applications typically have no synchronization context, continuations will typically be handled by the thread pool, so there is no issue if we block within the continuation.
WinForms or WPF, on the other hand, have synchronization context implemented on top of their message loop. Therefore, await executed on a UI thread will (eventually) execute its continuation on the UI thread as well. If we happen to block in the continuation, it will block the message loop and make the UI non-responsive until we unblock. OTOH, if we just await, it will neatly post continuations to be eventually executed on the UI thread, without ever blocking the UI thread.
In the following WinForms form, containing one button and one label, using await keeps the UI responsive at all times (note the async in front of the click handler):
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e) {
var result = await FooAsync();
label1.Text = result.ToString();
}
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = await t2;
return result1 + result2;
}
static Task<int> Method1Async() {
return Task.Run(
() => {
Thread.Sleep(3000);
return 11;
}
);
}
static Task<int> Method2Async() {
return Task.Run(
() => {
Thread.Sleep(5000);
return 22;
}
);
}
}
If we replaced the second await in FooAsync with t2.Result, it would continue to be responsive for about 3 seconds after the button click, and then freeze for about 2 seconds:
The continuation after the first await will politely wait its turn to be scheduled on the UI thread, which would happen after Method1Async() task finishes, i.e. after about 3 seconds,
at which point the t2.Result will rudely block the UI thread until the Method2Async() task finishes, about 2 seconds later.
If we removed the async in front of the button1_Click and replaced its await with FooAsync().Result it would deadlock:
The UI thread would wait on FooAsync() task to finish,
which would wait on its continuation to finish,
which would wait on the UI thread to become available,
which it isn't, since it is blocked by the FooAsync().Result.
The article "Await, SynchronizationContext, and Console Apps" by Stephen Toub was invaluable to me in understanding this subject.
With the code below, the final UI updates made in the final ContinueWith never take place. I think it is because of the Wait() I have at the end.
The reason I am doing that is because without the Wait, the method will return the IDataProvider before its finished being constructed in the background.
Can someone help me get this right?
Cheers,
Berryl
private IDataProvider _buildSQLiteProvider()
{
IDataProvider resultingDataProvider = null;
ISession session = null;
var watch = Stopwatch.StartNew();
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
// get the data
var buildProvider = Task.Factory
.StartNew(
() =>
{
// code to build it
});
// show some progress if we haven't finished
buildProvider.ContinueWith(
taskResult =>
{
// show we are making progress;
},
CancellationToken.None, TaskContinuationOptions.None, uiContext);
// we have data: reflect completed status in ui
buildProvider.ContinueWith(
dataProvider =>
{
// show we are finished;
},
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiContext);
try {
buildProvider.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
Console.WriteLine(e.Message);
}
Console.WriteLine("Exception handled. Let's move on.");
CurrentSessionContext.Bind(session);
return resultingDataProvider;
}
====
just to be clear
I am not having trouble talking to the ui thread. The first continue with updates the ui just fine. The trouble I am having is the timing of the last ui update and the return of the data provider.
I commented out some of the code to reduce the noise level in tis post and focus on the task sequencing.
====
ok, working code
private void _showSQLiteProjecPicker()
{
var watch = Stopwatch.StartNew();
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
ISession session = null;
// get the data
var buildProvider = Task.Factory.StartNew(
() =>
{
var setProgress = Task.Factory.StartNew(
() =>
{
IsBusy = true;
Status = string.Format("Fetching data...");
},
CancellationToken.None, TaskCreationOptions.None, uiScheduler);
var provider = new SQLiteDataProvider();
session = SQLiteDataProvider.Session;
return provider;
});
buildProvider.ContinueWith(
buildTask =>
{
if(buildTask.Exception != null) {
Console.WriteLine(buildTask.Exception);
}
else {
Check.RequireNotNull(buildTask.Result);
Check.RequireNotNull(session);
_updateUiTaskIsComplete(watch);
CurrentSessionContext.Bind(session);
var provider = buildTask.Result;
var dao = provider.GetActivitySubjectDao();
var vm = new ProjectPickerViewModel(dao);
_showPicker(vm);
}
},
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiScheduler);
}
UPDATE BELOW
This code doesn't look like it warrants TPL to me. Looks like maybe a good use for a BackgroundWorker instead!
Either way, the updates are probably not taking place because you can't update the UI from a separate thread -- you need to run the update on the UI thread. You should use the Dispatcher for this (http://stackoverflow.com/questions/303116/system-windows-threading-dispatcher-and-winforms contains info for both WPF and WinForms)
Update:
So I obviously missed some of the code so here's a revised answer. First of all, Nicholas is correct -- .ContinueWith returns a new task (http://msdn.microsoft.com/en-us/library/dd270696.aspx). So instead of
var result = Task.Factory.StartNew(...);
result.ContinueWith(...);
you probably want to create a new task and then make all the ContinueWith() calls and assign to the task and then call .Start() on the task. Something like:
var task = new Task(...).ContinueWith(...);
task.Start();
However, there is a flaw in the design to begin with (as I see it)! You're trying to run this code async, wihch is why you're using threads and TPL. However, you're calling buildProvider.Wait(); on the UI thread which blocks the UI thread until this task completes! Aside from the issue of repainting the UI in the ContinueWith() while the UI thread is blocked, there's no benefit to multithreading here since you're blocking the UI thread (a major no-no). What you probably want to do is stick the Bind()-ing inside a ContinueWith or something so that you don't have to call Wait() and block the UI thread.
My $0.02 is that if you expect the query to take a long time what you really want is 2 threads (or tasks in TPL)-- one to perform the query and one to update the UI at intervals with status. If you don't expect it to take so long I think you just want a single thread (Task) to query and then update the UI when it's done. I would probably do this via BackgroundWorker. TPL was built for managing lots of tasks and continuations and such but seems overkill for this kind of thing -- I think you could do it using a BackgroundWorker in a lot less code. But you mention you want to use TPL which is fine, but you're going to have to rework this a bit so that it actually runs in the background!
PS - you probably meant to put the Console.WriteLine("Exception handled. Let's move on."); inside the catch
I'm a little hazy, but last time I used the TPL I found it confusing. ContinueWith() returns a new Task instance. So you need to assign the second ContinueWith() result to a new variable, say var continuedTask = builderProvider.ContinueWith(...), and then change the last one to reference continuedTask.ContinueWith() instead of buildProvider.ContinueWith(). Then Wait() on the last Task.
Hope that helps!