Going through:
https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
and
How to bind WPF button to a command in ViewModelBase?
I've come up with the following code of reading and rendering file contents to a window asynchronously (or synchronously?):
class AppliedJobsViewModel
{
private TexParser texParser;
private ICommand _openTexClick;
public ICommand OpenTexClick
{
get
{
return _openTexClick ?? (_openTexClick = new CommandHandler(() => ReadAndParseTexFile(), () => CanExecute));
}
}
public bool CanExecute
{
get
{
// check if executing is allowed, i.e., validate, check if a process is running, etc.
return true;
}
}
public async Task ReadAndParseTexFile()
{
if (texParser == null)
{
texParser = new TexParser();
}
// Read file asynchronously here
await ReadAndParseTexFileAsync();
string[][] appliedJobs = texParser.getCleanTable();
}
private async Task ReadAndParseTexFileAsync()
{
texParser.ReadTexFile();
await Task.Delay(100);
}
public ObservableCollection<AppliedJob> AppliedJobs {
get;
set;
}
}
which "works" but I don't like that Task.Delay(100) (constant wait time).
VS also tells me at line:
return _openTexClick ?? (_openTexClick = new CommandHandler(() => ReadAndParseTexFile(), () => CanExecute));
"Because this call is not awaited, the execution of this method continues before the call is completed".
But this method is what binds the code to the wpf view. Isn't it async by default?
Just dropping an async in a method or task signature doesn't mean you're doing anything asynchronously.
Read this:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/using-async-for-file-access
Note that it is not just a case of adding async to the name than makes File.ReadAllTextAsync asynchronous.
You should read up on async and await.
eg
https://blog.stephencleary.com/2012/02/async-and-await.html
This is a complex subject. It will take careful reading and consideration to understand.
Once you've read that, reconsider your code.
In that warning your ide was telling you your code is synchronous.
You have synchronous code in there reading that file.
Sticking an await some-other-code in there does not make your file reading code asynchronous, it just means the ide sees an await Task. A pointless await task.
Now you know it's pointless.
Take out
await Task.Delay(100);
Replacing your file reading code with
string contents = await File.ReadAllTextAsync(filePath);
Could make the file reading asynchronous.
If this is a large file being read into memory then just reading it might have significant overhead and your UI may well remain responsive.
If you were doing some substantial processing of a file then you would probably do better pushing that onto a background thread.
You can do
await Task.Run(() => ProcessFileText(someurl));
Here ProcessFileText would be a Task or maybe Task<string[]> and return a string or string array. It would run on a background thread and return once completed.
Seeing as this is a different thread then it won't freeze your UI if it takes a while to do it's work.
Note that since it is now not on the UI thread this task cannot read or write UI properties or you'll get threading errors.
Code in the line(s) after that await is back on the ui thread.
Related
I want to call a task which itself call a async method which inturn returna bool value.
I want to do something on the basis of that outcome.
I can get the data on outcome.Result.Result but this does not look good and I wish to have the output in outcome.Result.
I can not figure it out.
Can someone please guide.
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome=Task.Factory.StartNew(() => mydata.UpdateValidated());
if (outcome.Result.Result)//This work fine but I think I need something to do so that outcome.Result gives my solution.
{ }
else { }
}
public async Task<bool> UpdateValidated()
{
var result= await Mediator.Send(new ValidatedEvent(this));
return result;
}
public async Task<bool> Handle(ValidatedEvent notification, CancellationToken cancellationToken)
{ //dO WORK
// return Task.FromResult(true);
return true;
}
Since UpdateValidated is already asynchronous, you should just call it directly to execute it. Things like Task.Factory.StartNew or Task.Run offer a way to put synchronous tasks on a new thread so that they can run asynchronously. So you should just call it directly:
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome = mydata.UpdateValidated()
// Note: this WILL block, regardless of how you call the async function
var result = outcome.Result;
}
You should try to avoid using .Result though, as this will block synchronous functions until the asynchronous result is ready, and may even cause deadlocks. If the OnValidated is a standard event handler, you could make it asynchronous instead and await your task:
private async void OnValidated(ValidatedIntergrationEvent evt)
{
var result = await mydata.UpdateValidated()
}
But this make this event handler fire and forget which can be dangerous. So you should really try to change your code that you are truly running asynchronously when calling asynchronous code.
Finally, note that you can force the asynchronous task onto a separate thread using Task.Run. This is useful when the asynchronous call also does a lot on the CPU:
var outcome = Task.Run(() => mydata.UpdateValidated());
This looks very similar to your Task.Factory.StartNew() call but returns only a Task<bool> instead of your Task<Task<bool>>. This is because Task.Run has an overload that explicitly allows you to call asynchronous methods which makes Task.Run just pass on the result.
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 have an async method that fetches some data from a database. This operation is fairly expensive, and takes a long time to complete. As a result, I'd like to cache the method's return value. However, it's possible that the async method will be called multiple times before its initial execution has a chance to return and save its result to the cache, resulting in multiple calls to this expensive operation.
To avoid this, I'm currently reusing a Task, like so:
public class DataAccess
{
private Task<MyData> _getDataTask;
public async Task<MyData> GetDataAsync()
{
if (_getDataTask == null)
{
_getDataTask = Task.Run(() => synchronousDataAccessMethod());
}
return await _getDataTask;
}
}
My thought is that the initial call to GetDataAsync will kick off the synchronousDataAccessMethod method in a Task, and any subsequent calls to this method before the Task has completed will simply await the already running Task, automatically avoiding calling synchronousDataAccessMethod more than once. Calls made to GetDataAsync after the private Task has completed will cause the Task to be awaited, which will immediately return the data from its initial execution.
This seems to be working, but I'm having some strange performance issues that I suspect may be tied to this approach. Specifically, awaiting _getDataTask after it has completed takes several seconds (and locks the UI thread), even though the synchronousDataAccessMethod call is not called.
Am I misusing async/await? Is there a hidden gotcha that I'm not seeing? Is there a better way to accomplish the desired behavior?
EDIT
Here's how I call this method:
var result = (await myDataAccessObject.GetDataAsync()).ToList();
Maybe it has something to do with the fact that the result is not immediately enumerated?
If you want to await it further up the call stack, I think you want this:
public class DataAccess
{
private Task<MyData> _getDataTask;
private readonly object lockObj = new Object();
public async Task<MyData> GetDataAsync()
{
lock(lockObj)
{
if (_getDataTask == null)
{
_getDataTask = Task.Run(() => synchronousDataAccessMethod());
}
}
return await _getDataTask;
}
}
Your original code has the potential for this happening:
Thread 1 sees that _getDataTask == null, and begins constructing the task
Thread 2 sees that _getDataTask == null, and begins constructing the task
Thread 1 finishes constructing the task, which starts, and Thread 1 waits on that task
Thread 2 finishes constructing a task, which starts, and Thread 2 waits on that task
You end up with two instances of the task running.
Use the lock function to prevent multiple calls to the database query section. Lock will make it thread safe so that once it has been cached all the other calls will use it instead of running to the database for fulfillment.
lock(StaticObject) // Create a static object so there is only one value defined for this routine
{
if(_getDataTask == null)
{
// Get data code here
}
return _getDataTask
}
Please rewrite your function as:
public Task<MyData> GetDataAsync()
{
if (_getDataTask == null)
{
_getDataTask = Task.Run(() => synchronousDataAccessMethod());
}
return _getDataTask;
}
This should not change at all the things that can be done with this function - you can still await on the returned task!
Please tell me if that changes anything.
Bit late to answer this but there is an open source library called LazyCache that will do this for you in two lines of code and it was recently updated to handle caching Tasks for just this sort of situation. It is also available on nuget.
Example:
Func<Task<List<MyData>>> cacheableAsyncFunc = () => myDataAccessObject.GetDataAsync();
var cachedData = await cache.GetOrAddAsync("myDataAccessObject.GetData", cacheableAsyncFunc);
return cachedData;
// Or instead just do it all in one line if you prefer
// return await cache.GetOrAddAsync("myDataAccessObject.GetData", myDataAccessObject.GetDataAsync);
}
It has built in locking by default so the cacheable method will only execute once per cache miss, and it uses a lamda so you can do "get or add" in one go. It defaults to 20 minutes sliding expiration but you can set whatever caching policy you like on it.
More info on caching tasks is in the api docs and you may find the sample app to demo caching tasks useful.
(Disclaimer: I am the author of LazyCache)
I'm making a windows phone game with Unity3d and I have the need to call a method from the Unity thread asynchronously from the UI thread.
This all works, however with one particular method the first execution executes as expected however after the second it seems to lock up the game.
private async static Task<String> ShowDescriptionProductListing()
{
var x = await CurrentApp.LoadListingInformationAsync();
StringBuilder builder = new StringBuilder();
builder.AppendFormat("{0}\n{1}", x.Description,
x.ProductListings.FirstOrDefault().Value);
return builder.ToString();
}
public static void ShowDescrProduct()
{
string x = ShowDescriptionProductListing().Result;
MessageBox.Show(x);
}
I think the line:
var x = await CurrentApp.LoadListingInformationAsync();
Is most likely the culprit, however I'm having a hard time debugging it.
The class which 'holds' that method in unity is like so:
public static class HelperClass
{
public static void ShowDescrProduct()
{
Dispatcherr.InvokeOnUIThread(Tests.ShowDescrProduct); //The method above
}
}
Dispatcherr (Yeah i need to use namespaces haha) just holds two Action properties that I set inside the UI thread.
public void EnterUIThread(Action action)
{
Dispatcher.BeginInvoke(() =>
{
action();
});
}
private void Unity_Loaded()
{
Dispatcherr.InvokeUIThread = EnterUIThread; //One of the actions I just
//mentioned being assigned the above
//method
}
And it's in the EnterUIThread call to Dispatcher.BeginInvoke that it seems to get locked up, only after the first call - which is always successful.
Confusing me slightly to say the least.
Anyone able to give any insight?
Thanks in advance
You're calling Result on the asynchronous operation. This is going to cause the UI thread to block until the asynchronous operation finishes. The asynchronous operation needs to wait for the UI thread to be free so that the continuation to LoadListingInformationAsync can be scheduled in the UI thread.
Both operations are waiting on each other to finish. Deadlock.
You need to not block the UI thread while waiting for this operation to finish. You should await it instead, making ShowDescrProduct and async method.
I'm trying to transition from the Event-based Asynchronous Pattern where I tracked running methods using unique id's and the asynoperationmanager. As this has now been dropped from Windows 8 Apps I'm trying to get a similar effect with Async/Await but can't quite figure out how.
What I'm trying to achieve is something like
private async Task updateSomething()
{
if(***the method is already running***)
{
runagain = true;
}
else
{
await someMethod();
if (runagain)
{
run the method again
}
}
}
The part I'm struggling with is finding out if the method is running. I've tried creating a Task and looking at the status of both that and the .status of the async method but they don't appear to be the correct place to look.
Thanks
UPDATE: This is the current code I use in .net 4 to achieve the same result. _updateMetaDataAsync is a class based on the Event-Based Asynchronous Pattern.
private void updateMetaData()
{
if (_updateMetaDataAsync.IsTaskRunning(_updateMetaDataGuid_CheckAllFiles))
{
_updateMetaDataGuid_CheckAllFiles_Again = true;
}
else
{
_updateMetaDataGuid_CheckAllFiles_Again = false;
_updateMetaDataAsync.UpdateMetaDataAsync(_updateMetaDataGuid_CheckAllFiles);
}
}
private void updateMetaDataCompleted(object sender, UpdateMetaDataCompletedEventArgs e)
{
if (_updateMetaDataGuid_CheckAllFiles_Again)
{
updateMetaData();
}
}
async/await itself is intended to be used to create sequential operations executed asynchronously from the UI thread. You can get it to do parallel operations, but generally the operations "join" back to the UI thread with some sort of result. (there's also the possibility of doing "fire-and-forget" types of asynchronous operations with await but it's not recommended). i.e. there's nothing inherent to async/await to support progress reporting.
You can get progress out of code using async/await; but you need to use new progress interfaces like IProgress<T>. For more info on progress reporting with async/await, see http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx. Migrating to this should just be a matter of calling an IProgress delegate instead of a Progress event.
If you're using a Task you've created, you can check the Task's Status property (or just see Task.IsCompleted if completion is the only state you are interested in).
That being said, await will not "return" until the operation either completes, raises an exception, or cancels. You can basically safely assume that, if you're still waiting on the "await", your task hasn't completed.
SemaphoreSlim queueToAccessQueue = new SemaphoreSlim(1);
object queueLock = new object();
long queuedRequests = 0;
Task _loadingTask;
public void RetrieveItems() {
lock (queueLock) {
queuedRequests++;
if (queuedRequests == 1) { // 1 is the minimum size of the queue before another instance is queued
_loadingTask = _loadingTask?.ContinueWith(async () => {
RunTheMethodAgain();
await queueToAccessQueue.WaitAsync();
queuedRequests = 0; // indicates that the queue has been cleared;
queueToAccessQueue.Release()
}) ?? Task.Run(async () => {
RunTheMethodAgain();
await queueToAccessQueue.WaitAsync();
queuedRequests = 0; // indicates that the queue has been cleared;
queueToAccessQueue.Release();
});
}
}
}
public void RunTheMethodAgain() {
** run the method again **
}
The added bonus is that you can see how many items are sitting in the queue!