How to prove different execution order in an obvious way - c#

I'd like to demonstrate in a bluntly obvious way how this asynchronous sample:
Thing[] stuff = await Context.Things
.Where(a => true)
.ToArrayAsync();
Console.WriteLine("Beep");
will execute in a different order than they synchronous version:
Thing[] stuff = Context.Things
.Where(a => true)
.ToArray();
Console.WriteLine("Boop");
I'd like to show that the second version always creates the array before the printout while the first one may perform differently.
Not sure how to do it obviously clear.

I'd like to demonstrate in a bluntly obvious way how this asynchronous sample:
will execute in a different order than they synchronous version
But you can't because both versions will create array before the Console.WriteLine("Boop");. In the first sample await will stop the method execution until the asynchronous operation will finish.
Such experiments are not that easy with db contexts because you will need some side effect. Much easier to use Task.Delay for async simulation;
Your first snippet can be changed to:
var array = await Task.Run(async () =>
{
await Task.Delay(500); // simulate db call
Console.WriteLine("Array created");
return new int[]{};
});
Console.WriteLine("Beep");
Then you can compare it with:
var task = Task.Run(async () =>
{
await Task.Delay(500); // simulate db call
Console.WriteLine("Array created");
return new int[]{};
});
Console.WriteLine("Beep");
var array = await task;
As for trying to prove async nature of EF Core calls (1. assuming you are using this ORM 2. assuming that you are not querying Oracle database which AFAIK still does not provide truly async client) you will need to find a way to inject your side effect. For relatively easy way to do this you can look into EF Core Interceptors or events like ChangeTracker.Tracked or just enabling logging and/or using diagnostic listener.
For example (should work in EF7):
class ObjectCreatedLoggerInterceptor : IMaterializationInterceptor
{
public object CreatedInstance(MaterializationInterceptionData materializationData, object entity)
{
Console.WriteLine("Array element created");
return entity;
}
}
public class SomeContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.AddInterceptors(new ObjectCreatedLoggerInterceptor());
base.OnConfiguring(optionsBuilder);
}
}
Which will write "Array element created" every time an object is created by EF (query should return at least one record).

You have to modify first example as following to prove it.
var task = Context.Things
.Where(a => true)
.ToArrayAsync();
Console.WriteLine("Beep");
Thing[] stuff = await task;
In this example, ToArray will be executed after the console as task is awaited later on.

Related

Func doesn't work & blocked during test execution

Prerequisites:
.Net 6.0
C# 10
NUnit 3.13.3
Context:
Try to run an unit test, but run into some kind of thread blocker. The code just stop execution on
value = await getDataToCacheAsync.Invoke();
The last row that can be debugged is
return () => new Task<string?>(() => cacheValue [there]);
Q: It looks like there is some kind of deadlock happened, but it's not clear for me why and how it can be addressed
Unit test:
[Test]
public async Task GetCachedValueAsync_WithDedicatedCacheKey_ReturnsExpectedCacheValue()
{
const string cacheKey = "test-cache-key";
const string cacheValue = "test-cache-key";
var result = await _sut.GetCachedValueAsync(cacheKey, GetDataToCacheAsync(cacheValue));
Assert.AreEqual(cacheValue, result);
}
private static Func<Task<string?>> GetDataToCacheAsync(string cacheValue)
{
return () => new Task<string?>(() => cacheValue);
}
The code under test:
public async Task<T?> GetCachedValueAsync<T>(string cacheKey, Func<Task<T?>> getDataToCacheAsync)
where T : class
{
// [Bloked here, nothing happens then, I'm expecting that it should return "test-cache-value"]
value = await getDataToCacheAsync.Invoke(); [Blocked]
...
return value
}
After
return () => new Task<string?>(() => cacheValue [there]);
was replaces with
return () => Task.FromResult(cacheValue);
it started work
UPD:
It seems like the root cause is that a task should be started directly before awaiting it, in such cases (e.g. Task.Run(...), TaskFactory ... etc.).
Task.FromResult returns already completed task with a result
As written in the docs generally you should try to avoid creating tasks via constructor:
This constructor should only be used in advanced scenarios where it is required that the creation and starting of the task is separated.
Rather than calling this constructor, the most common way to instantiate a Task object and launch a task is by calling the static Task.Run(Action) or TaskFactory.StartNew(Action) method.
The issue being that task created by constructor is a "cold" one (and according to guidelines you should avoid returning "cold" tasks from methods, only "hot" ones) - it is not started so await will result in endless wait (actually no deadlock happening here).
There are multiple ways to fix this code, for example:
Use Task.Run:
return () => Task.Run(() => cacheValue);
Start created task manually (though in this case there is no reason to. Also as noted by #Theodor Zoulias - it is recommended to specify explicitly the scheduler when calling the Start method. Otherwise the task will be scheduled on the ambient TaskScheduler.Current, which can be a source of some issues):
return () =>
{
var task = new Task<string?>(() => cacheValue);
task.Start();
return task;
}
Return a completed task (which I think is the best way in this case, unless you are testing a very specific scenario):
return () => Task.FromResult(cacheValue);

Run async/await method on other than UI thread [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a WPF app with an EF connection to a database. But when I call await DbSet().SingleAsync() my UI thread is stuck and not responsive. I figured out that when I ran await it will still run on main UI thread so I can access UI. That will explain why it is working when I use only Task.Delay(), because SingleAsync is using thread, but Task.Delay() doesn't.
ConfigureAwait(false) should solve this and run it on different thread. But it doesn't and my UI still freeze.
Am I doing it wrong ?
Code:
private async void Button_Login_Click(object sender, RoutedEventArgs e)
{
await userService.ValidateCredentials(textBoxLogin.Text, textBoxLogin.Text).ConfigureAwait(false);
}
public async Task<bool> ValidateCredentials(string username, string password)
{
User user = await userDao.SingleOrNull(true, o => o.Username == username && o.Password == password);
if (user == null)
return (false);
return (true);
}
public async Task<ResourceDbType> SingleOrNull(bool noTracking, Expression<Func<ResourceDbType, bool>> where)
{
ResourceDbType ret;
try
{
if (noTracking)
{
ret = await GetDbSet().AsNoTracking().SingleAsync(where);
}
else
ret = await GetDbSet().SingleAsync(where);
}
catch (Exception ex)
{
return null;
}
return ret;
}
EDIT:
BaseDao should only expose functions from DbContext with selected DbSet model registered at MainDbContext. We are using this code at work at RestApi service, so I reused it because I am used to it.
[RegisterClass(Lifetime.Scoped)] is atribute for marking class to Register it in DependencyInjection at start of app with reflection.
Dao code:
public class BaseDao<ResourceDbType> : IDisposable where ResourceDbType : class, new()
{
public DbContext DbContext { get; protected set; }
public BaseDao(MainDbContext mainDbContext)
{
DbContext = mainDbContext;
}
public DbSet<ResourceDbType> GetDbSet()
{
return this.DbContext.Set<ResourceDbType>();
}
public List<ResourceDbType> ToList()
{
return this.GetDbSet().ToList();
}
public ResourceDbType[] ToArray()
{
return this.GetDbSet().ToArray();
}
public async Task<ResourceDbType> SingleOrNull(bool noTracking, Expression<Func<ResourceDbType, bool>> where)
{
ResourceDbType ret;
try
{
if (noTracking)
{
ret = await GetDbSet().AsNoTracking().SingleAsync(where);
}
else
ret = await GetDbSet().SingleAsync(where);
}
catch (Exception ex)
{
return null;
}
return ret;
}
public void Dispose()
{
this.DbContext?.Dispose();
}
}
UserDao Code:
[RegisterClass(Lifetime.Scoped)]
public class UserDao : BaseDao<User>
{
public UserDao(MainDbContext mainDbContext) : base(mainDbContext)
{
}
}
Async is not a silver bullet, and from what I see from the example, it is most likely unnecessary. Async is not ideal for "use everywhere, every time" but rather for potentially mitigating expensive operations.
By tucking away EF behind a service and then a repository makes your EF operations a lot less efficient than they could be.
For example: Without a repository level. (Trust EF to be used by the service, and injected into the service)
// UI
private void Button_Login_Click(object sender, RoutedEventArgs e)
{
var result = userService.ValidateCredentials(textBoxLogin.Text, textBoxLogin.Text);
}
// Service
public bool ValidateCredentials(string username, string password)
{
var result = Context.Users.Any(x => x.UserName == userName && x.Password == password);
return result;
}
EF can generate a very efficient EXISTS query rather than loading an entity just to check if a row exists. Faster code without needing to worry about handing it off.
If you want to be able to unit test the service, then you can introduce a repository. I recommend leveraging IQueryable:
// Service
public bool ValidateCredentials(string username, string password)
{
using (var unitOfWork = UnitOfWorkFactory.Create())
{
var result = UserRepository.FindUserByName(username, password).Any();
return result;
}
}
// Repository
public IQueryable<User> FindUserByName(string userName, string password)
{
var query = Context.Users.Where(x => x.UserName == userName && x.Password == password);
return query;
}
The repository can guard access to the Entities to ensure required rules are followed etc. yet can be more easily mocked out than the DbContext. This requires consideration for scoping the DbContext in a Unit of Work to facilitate the Service to control the boundary of the DbContext and interact with the resulting entities returned by the Repository. The implementation I use for that with EF is Medhime's DbContextScope. (There are forks available for EF Core) This gives the service full control over how the entities are consumed with the repository enforcing the rules and making mocking simpler.
Side Note: Some devs don't like that the services need to be aware of EF concerns (such as legal Lambdas that EF can understand) but this is a trade off for a thinner, much more flexible Repository. (Handling additional criteria, projection, sorting, paging, etc. is a snap however a particular consumer needs.) I've seen many attempts to abstract away EF to accept criteria, sorting, projection, and paging into repository methods using Func etc. but the reality is that these are quite complex and still have to adhere to EF's rules anyways. Ultimately when you choose to use EF you need to trust it as part of your solution in order to leverage it to it's fullest.
Async is geared more towards particularly expensive operations. WPF's synchronization context essentially supports interacting with async code, but since this is going to ensure code resumes on the UI thread, there is arguably little benefit using it other than facilitating it to be able to await async methods. This is more to facilitate an event handler to work properly when calling and awaiting several async operations.
I.e.
private async void Button_Login_Click(object sender, RoutedEventArgs e)
{
var firstTask = userService.DoSomethingThatMightTake5SecondsAsync(); // Don't actually name your tasks this! :)
var secondTask = userService.DoSomethingThatMightTake5SecondsAsync();
var thirdTask = userService.DoSomethingThatMightTake5SecondsAsync();
// Do stuff that doesn't rely on those 3 tasks....
var firstResult = await firstTask;
// Do something with first task results
var secondResult = await secondTask;
// Do something with second task results
var thirdResult = await thirdTask;
// Do something with third task results
}
Synchronously, those 3 operations would take 15 seconds and whatever else needs to happen that doesn't rely on them would have to wait until they complete. Asynchronously they could complete faster, and independent code could execute while they are processing.
Though caution would be needed in the above example with EF as things like the DbContext is not thread safe so kicking off 3 async methods that result in the use of a single DbContext would result in calls to the DbContext by multiple threads. Awaiting them in turn with a UI Thread Sync context is effectively the same as sync calls, only marginally slower. (Overhead of spawning the thread pool threads and waiting for the sync context)
Using async should be situational.
Edit: Example with Async vs. Sync:
With a simple WPF form with 2 buttons and a text box (uxEntry). One button for a Synchronous event, one with an Asynchronous event. The textbox will receive focus after one of the buttons is called and you can try typing in it to see if the UI thread is responding:
private async void AsyncButton_Click(object sender, RoutedEventArgs e)
{
uxEntry.Focus();
var result = await DoSomethingAsync();
MessageBox.Show(result);
}
private void SyncButton_Click(object sender, RoutedEventArgs e)
{
uxEntry.Focus();
var result = DoSomethingSync();
MessageBox.Show(result);
}
private async Task<string> DoSomethingAsync()
{
await Task.Run(() =>
{
Thread.Sleep(5000);
});
return "Done";
}
private string DoSomethingSync()
{
Thread.Sleep(5000);
return "Done";
}
In the case where you click the Sync button, the text box won't receive focus or accept input until the 5 seconds is up. In the Async example, it will respond immediately while the async task is running. Async events allow the UI thread to continue responding to events which can make your app feel more responsive, however combining this with EF DbContexts, which are not thread safe, can lead to issues.
Using Async to parallelize operations would be dangerous with code using a single injected DbContext reference, for example:
private async void AsyncMultiButton_Click(object sender, RoutedEventArgs e)
{
uxEntry.Focus();
var task1 = DoSomethingAsync();
var task2 = DoSomethingAsync();
var task3 = DoSomethingAsync();
var result1 = await task1;
var result2 = await task2;
var result3 = await task3;
var message = string.Format("Task1: {0} Task2: {1} Task3: {2}", result1, result2, result3);
MessageBox.Show(message);
}
If DoSomethingAsync talked to a repository DbContext those 3 tasks would all start simultaneously, and the DbContext will not like that. Depending on the code it can lead to headaches as it appears to work sometimes or in debug environments only to crash with errors at others or in production. The solution would be to await each one in turn:
uxEntry.Focus();
var result1 = await DoSomethingAsync();
var result2 = await DoSomethingAsync();
var result3 = await DoSomethingAsync();
This would be safe for the DbContext, and the UI would be responsive, however that would now take 15 seconds to complete. It can be tempting to kick them off in parallel, just something to be cautious of when using async. It can be useful for making your application appear more responsive, but be cautious when thinking it can make your application "faster".
Looking at your original code example I don't see a glaring reason why the awaited event handler would still appear to lock up the UI, though that may be some difference between your current code and the example you provided.

How to run multiple call with-in a function parallel

I have a few functions that build a user response class and I am still grasping the TASK async await.
From the code below is there a way to run all the all in parallel rather than one at a time?
I guess my first question should be how is the call taking place the way it is set up now?
My second question is how can i run all these calls in parallel?
It is not necessary for the returns to return in any specific order
public static async Task<ProjectForDrawings> GetProjectInfo(string cnn, int projectID)
{
return await Task.Run(() =>
{
ProjectForDrawings projectForDrawings = DataBase.proc_GetProject_ForDrawings.ToRecord<ProjectForDrawings>(cnn, projectID);
projectForDrawings.Submittals = DataBase.proc_GetSubmittal.ToList(cnn, projectID);
projectForDrawings.ProjectLeafs = DataBase.proc_GetProjectLeafs.ToList<ProjectLeaf>(cnn, projectID);
projectForDrawings.Revisions = DataBase.proc_GetRevisionsForProject.ToList<Revisions>(cnn, projectID);
return projectForDrawings;
});
}
how is the call taking place the way it is set up now?
It schedules the work to a background thread (Task.Run) and then asynchronously waits for it to complete (await). The work will execute each database proc one at a time, synchronously blocking the background thread until it completes.
how can i run all these calls in parallel?
You can start all the tasks, and then await them all with Task.WhenAll:
public static async Task<ProjectForDrawings> GetProjectInfo(string cnn, int projectID)
{
ProjectForDrawings projectForDrawings = DataBase.proc_GetProject_ForDrawings.ToRecord<ProjectForDrawings>(cnn, projectID);
var submittalsTask = Task.Run(() => DataBase.proc_GetSubmittal.ToList(cnn, projectID));
var leafsTask = Task.Run(() => DataBase.proc_GetProjectLeafs.ToList<ProjectLeaf>(cnn, projectID));
var revisionsTask = Task.Run(() => DataBase.proc_GetRevisionsForProject.ToList<Revisions>(cnn, projectID));
await Task.WhenAll(submittalsTask, leafsTask, revisionsTask);
projectForDrawings.Submittals = await submittalsTask;
projectForDrawings.ProjectLeafs = await leafsTask;
projectForDrawings.Revisions = await revisionsTask;
return projectForDrawings;
}
However, many (most?) databases do not allow multiple queries per database connection, so this may not work for your database. Also, it may not be a good idea to parallelize calls on the database in the first place - it is possible to cause a self-imposed denial-of-service. Finally, using Task.Run in the implementation is not a good pattern (for reasons I describe on my blog) - using natural async methods would be better.

will Task.Run() make any difference in performance?

I have a method which calls database as shown below:
BL Method to call DAO method:
public async Task<List<Classes>> GetClassesAndAddRules(string classId)
{
var classData = await Task.Run( () => _daoClass.GetClasses(classId));
//logic for adding rule
//..................................
}
DatabaseCall in DAO:
//*below method takes 1 second approx to return*
public List<Classes> GetClasses(string id)
{
var retVal = new List<Classes>();
using (var context = new test_db_context())
{
var rows = context.GetClassesById(id);
foreach (ClassesDBComplexType row in rows)
{
retVal.Add(Mapper.Map<GetClassesByClassIdOut>(row));
}
}
return retVal;
}
Is there any performance boost just my calling the DAO method using await ?
My understanding is GetClasses() will be called on a separate thread so that it doesn't block and continue processing other stuff.
Any help is appreciated.
The code you posted won't compile. From the title of your question, I'm assuming that your call actually looks like await Task.Run(() => _daoClass.GetClasses(classId));
In that case, the use of Task.Run will make a difference in performance: it will be worse.
The point of async on the server side is to free up the request thread instead of blocking it. What you're doing with await Task.Run(...) is to free up the request thread by starting work on another thread. In other words, the Task.Run code has the same amount of work to do plus thread marshaling.

c# simple background thread

I am looking for a simple way to do a task in background, then update something (on the main thread) when it completes. It's in a low level 'model' class so I can't call InvokeOnMainThread as I don't have an NSObject around. I have this method:
public void GetItemsAsync(Action<Item[]> handleResult)
{
Item[] items=null;
Task task=Task.Factory.StartNew(() =>
{
items=this.CreateItems(); // May take a second or two
});
task.ContinueWith(delegate
{
handleResult(items);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
This seems to work OK, but
1) Is this the best (simplest) way?
2) I'm worried about the local variable:
Item{} items=null
What stops that disappearing when the method returns before the background thread completes?
Thanks.
I think your method slightly violates a Single Responsibility Principle, because it doing too much.
First of all I suggest to change CreateItems to return Task instead of wrapping it in the GetItemsAsync:
public Task<Item[]> CreateItems(CancellationToken token)
{
return Task.Factory.StartNew(() =>
// obtaining the data...
{});
}
CancellationToken is optional but can help you if you able to cancel this long running operation.
With this method you can remove GetItemsAsync entirely because its so simple to handle results by your client without passing this delegate:
// Somewhere in the client of your class
var task = yourClass.CreateItems(token);
task.ContinueWith(t =>
// Code of the delegate that previously
// passed to GetItemsAsync method
{}, TaskScheduler.FromCurrentSynchronizationContext());
Using this approach you'll get more clear code with only one responsibility. Task class itself is a perfect tool for representing asynchronous operation as a first class object. Using proposed technique you can easily mock you current implementation with a fake behavior for unit testing without changing your clients code.
Something like this:
public void GetItemsAsync(Action<Item[]> handleResult)
{
int Id = 11;
Task<Item[]> task = Task.Factory.StartNew(() => CreateItems(Id)); // May take a second or two
task.ContinueWith(t => handleResult(t.Result), TaskScheduler.FromCurrentSynchronizationContext());
}
Your code looks fine.
It's a perfect example of when to use async / await if you can use C# 5, but if not, you have to write it as you have done with continuations.
The items variable is captured in your lambdas, so that's fine too.
When you write a lambda that uses an outside variable, the C# compiler creates a class that contains the variable. This is called a closure and means you can access the variable inside your lambda.
Here is a nicer soultion:
public void GetItemsAsync(Action<Item[]> handleResult)
{
var task = Task.Factory.StartNew<Item[]>(() =>
{
return this.CreateItems(); // May take a second or two
});
task.ContinueWith(delegate
{
handleResult(task.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
}

Categories

Resources