I am trying to speed up some code of mine,
I make 2 or 3 reads to a slow database, and I want to make these calls run in paralle.
FSKWebInterfaceEntities dbSrc = new FSKWebInterfaceEntities();
public void main()
{
var TaskUsr = GetUserAsync(dev);
var TaskOldCompany = GetOldCompanyAsync(dev);
await Task.WhenAll();
var usr = TaskUsr.Result;
var oldCompanyName = TaskOldCompany.Result;
.....
use my two variables to insert a new entry into my localdb
}
private async Task<ut_User> GetUserAsync(ut_UserAPNdevices dev)
{
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
}
private async Task<String> GetOldCompanyAsync(ut_UserAPNdevices dev)
{
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID).Company;
}
On my two helper methods its is underlined green and said that there is no await, and therefore will run synchronously. However I cant return return await dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
How should I modify my code to make the two reads in parallel?
You can await that line because it is not an async method. You can't really await database calls as they are not thread safe. See this thread for an example of a way to do it, and a better explanation as to why not. You can consider using SqlCommands that have async methods as well.
You cannot use the same EF DbContext concurrently. From the EF Team's statement about thread safety:
For the moment, EF will detect if the developer attempts to execute
two async operations at one time and throw.
You still can call them asynchronously, but sequentially:
public async Task main()
{
var sr = await GetUserAsync(dev);
var oldCompany = await GetOldCompanyAsync(dev);
.....
use my two variables to insert a new entry into my localdb
}
Updated to address the comment:
Could you possible post a simple example of how I would change my
above code to use the multiple dbcontext, As I don't really know the
correct way to do it, I would be coding in the dark.
Something like below. I'm not an expert in EF to assure you this will actually improve the processing time. There may be significant overhead of opening the database connection for each context.
public async Task main()
{
var TaskUsr = GetUserAsync(dev);
var TaskOldCompany = GetOldCompanyAsync(dev);
await Task.WhenAll(TaskUsr, TaskOldCompany);
var usr = TaskUsr.Result;
var oldCompanyName = TaskOldCompany.Result;
.....
use my two variables to insert a new entry into my localdb
}
private async Task<ut_User> GetUserAsync(ut_UserAPNdevices dev)
{
using (var dbSrc = new FSKWebInterfaceEntities())
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
}
private async Task<String> GetOldCompanyAsync(ut_UserAPNdevices dev)
{
using (var dbSrc = new FSKWebInterfaceEntities())
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID).Company;
}
Related
I'm not sure if this code is Asynchronous. I call this function using await from my main controller and within the function I use await on the LINQ query and .ToListAsync() - but after the query I have the foreach loop which may defeat the purpose of async on the query.
Main Controller Call:
case "getassets":
reply = await GetAssets();
break;
Function:
public async Task<ReplyObj> GetAssets()
{
ReplyObj obj = new ReplyObj();
obj.Result = new List<dynamic>();
dynamic AssetRecords = await _context.Asset.FromSql("SELECT * FROM Asset").ToListAsync();
foreach (var objAsset in AssetRecords)
{
obj.Result.Add(new Asset()
{
AssetId = objAsset.AssetId,
Name = objAsset.Name,
Description = objAsset.Description,
PriceDecimals = objAsset.PriceDecimals
});
}
obj.Success = true;
obj.Message = "";
return obj;
}
This call will have many requests hitting it, I want to know for sure that its using async correctly. Thank you!
To begin, here's a couple of references for async/await in C# that I'd suggest reviewing:
Microsoft Docs
SO Community Answer
The simple (high-level) answer is that awaiting your sql call will return control up the call stack and continue execution. In this case, that means it will go up to:
reply = await GetAssets();
Which will in turn return control to whatever function called that, etc. etc..
With that said, if all of your async calls in your call stack are immediately being awaited, then async won't end up buying you anything/changing the flow of control. To say, keep in mind that async != threading.
Few things that I want to point out:
dynamic AssetRecords = await _context.Asset.FromSql("SELECT * FROM Asset").ToListAsync(); When you are using _context.Asset it will return all the Asset rows that you have. Why would you execute another query on the table when the Asset it self is giving all that you need? Hence, to me this is redundant thing.
And if you use select method and then get the list asyncronously then you will have eliminated the the foreach loop and it will cost only one await call and query processing. See code sample below:
public async Task<ReplyObj> GetAssets()
{
ReplyObj obj = new ReplyObj();
return obj.Result = await _context.Asset.Select(s => new
{
AssetId = s.AssetId,
Name = s.Name,
Description = s.Description,
PriceDecimals = s.PriceDecimals
}).ToListAsync();
}
This could now be your true async method.
PS:
If you want to show your code to experts for review, I would suggest joining StackExchange CodeReview Community
I have the following code, that I intend to run asynchronously. My goal is that GetPictureForEmployeeAsync() is called in parallel as many times as needed. I'd like to make sure that 'await' on CreatePicture does not prevent me from doing so.
public Task<Picture[]> GetPictures(IDictionary<string, string> tags)
{
var query = documentRepository.GetRepositoryQuery();
var employees = query.Where(doc => doc.Gender == tags["gender"]);
return Task.WhenAll(employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)));
}
private Task<Picture> GetPictureForEmployeeAsync(Employee employee, IDictionary<string, string> tags)
{
var base64PictureTask = blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var documentTask = documentRepository.GetItemAsync(employee.ID.ToString());
return CreatePicture(tags, base64PictureTask, documentTask);
}
private static async Task<Picture> CreatePicture(IDictionary<string, string> tags, Task<string> base64PictureTask, Task<Employee> documentTask)
{
var document = await documentTask;
return new Picture
{
EmployeeID = document.ID,
Data = await base64PictureTask,
ID = document.ID.ToString(),
Tags = tags,
};
}
If I understand it correctly, Task.WhenAll() is not affected by the two awaited tasks inside CreatePicture() because GetPictureForEmployeeAsync() is not awaited. Am I right about this? If not, how should I restructure the code to achieve what I want?
I'd like to make sure that 'await' on CreatePicture does not prevent me from doing so.
It doesn't.
If I understand it correctly, Task.WhenAll() is not affected by the two awaited tasks inside CreatePicture() because GetPictureForEmployeeAsync() is not awaited. Am I right about this?
Yes and no. The WhenAll isn't limited in any way by the awaited tasks in CreatePicture, but that has nothing to do with whether GetPictureForEmployeeAsync is awaited or not. These two lines of code are equivalent in terms of behavior:
return Task.WhenAll(employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)));
return Task.WhenAll(employees.Select(async employee => await GetPictureForEmployeeAsync(employee, tags)));
I recommend reading my async intro to get a good understanding of how async and await work with tasks.
Also, since GetPictures has non-trivial logic (GetRepositoryQuery and evaluating tags["gender"]), I recommend using async and await for GetPictures, as such:
public async Task<Picture[]> GetPictures(IDictionary<string, string> tags)
{
var query = documentRepository.GetRepositoryQuery();
var employees = query.Where(doc => doc.Gender == tags["gender"]);
var tasks = employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)).ToList();
return await Task.WhenAll(tasks);
}
As a final note, you may find your code cleaner if you don't pass around "tasks meant to be awaited" - instead, await them first and pass their result values:
async Task<Picture> GetPictureForEmployeeAsync(Employee employee, IDictionary<string, string> tags)
{
var base64PictureTask = blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var documentTask = documentRepository.GetItemAsync(employee.ID.ToString());
await Task.WhenAll(base64PictureTask, documentTask);
return CreatePicture(tags, await base64PictureTask, await documentTask);
}
static Picture CreatePicture(IDictionary<string, string> tags, string base64Picture, Employee document)
{
return new Picture
{
EmployeeID = document.ID,
Data = base64Picture,
ID = document.ID.ToString(),
Tags = tags,
};
}
The thing to keep in mind about calling an async method is that, as soon as an await statement is reached inside that method, control immediately goes back to the code that invoked the async method -- no matter where the await statement happens to be in the method. With a 'normal' method, control doesn't go back to the code that invokes that method until the end of that method is reached.
So in your case, you can do the following:
private async Task<Picture> GetPictureForEmployeeAsync(Employee employee, IDictionary<string, string> tags)
{
// As soon as we get here, control immediately goes back to the GetPictures
// method -- no need to store the task in a variable and await it within
// CreatePicture as you were doing
var picture = await blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var document = await documentRepository.GetItemAsync(employee.ID.ToString());
return CreatePicture(tags, picture, document);
}
Because the first line of code in GetPictureForEmployeeAsync has an await, control will immediately go right back to this line...
return Task.WhenAll(employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)));
...as soon as it is invoked. This will have the effect of all of the employee items getting processed in parallel (well, sort of -- the number of threads that will be allotted to your application will be limited).
As an additional word of advice, if this application is hitting a database or web service to get the pictures or documents, this code will likely cause you issues with running out of available connections. If this is the case, consider using System.Threading.Tasks.Parallel and setting the maximum degree of parallelism, or use SemaphoreSlim to control the number of connections used simultaneously.
I'm introducing asynchronous programming to my existing code base and having some trouble with calling Select() on the result of GetStudents() - the error message received is as follows "Task<List<ApplicationUser>> does not contain a defintion for Select". I think it'll be due to incorrect syntax, but any guidance would be appreciated - thanks.
public async Task<List<ApplicationUser>> GetStudents()
{
return await Task.Run(() => _context.Users.ToList());
}
public async Task<StudentIndexViewModel> CreateStudentRegisterViewModel()
{
var model = new StudentIndexViewModel();
var students = await _studentRepo.GetStudents().
Select(x => new StudentViewModel
{
Forename = x.Forename,
Surname = x.Surname
}).ToListAsync();
model.Students = students;
return model;
}
As it was mentioned, the error comes from trying to call Select on a Task<T>, which is not valid. However, the problem is much bigger than that. The code is currently getting the entire table from the database just to get a few values from the result in-memory. This is a waste of processing time in both the database and the application server.
Not only that, but also using a thread pool thread just to wait on an I/O operation is another waste.
Overall, the code should be something like this.
public async Task<List<ApplicationUser>> GetApplicationUsersAsync()
{
// use Entity Framework properly with ToListAsync
// this returns the entire table
return await _context.Users.ToListAsync();
}
public async Task<List<StudentViewModel>> GetStudentsAsync()
{
// use Entity Framework properly with ToListAsync
return await _context.Users
// this only returns the 2 needed properties
.Select(x => new StudentViewModel
{
Forename = x.Forename,
Surname = x.Surname
})
.ToListAsync();
}
public async Task<StudentIndexViewModel> CreateStudentRegisterViewModel()
{
var model = new StudentIndexViewModel();
model.Students = await _studentRepo.GetStudentsAsync();
return model;
}
_studentRepo.GetStudents() returns a Task<List<...>>.
As the error is telling you, Task isn't a collection and doesn't have a Select() method.
You can use await to get the collection inside the task, but you need to call Select() on the awaited value (your code currently awaits Select()).
You need to add parentheses:
(await ...).Select(...);
Sorry for a subjective question like this:
I current have a sequential loading method which was extremely slow, I have converted this into a async method:
public async void LoadData(int releaseId, int projectId, bool uiThread)
Within this method I start up an Await task (and set the ConfigureAwait to be false) as it does not need to capture and resume from this context.
await Task.Run(() =>
{
//make several DB calls as below
}).ConfigureAwait(False);
Within this task I make several async calls to EF / the database, each call looks something like this:
public async virtual Task<List<X>> FindXAsync()
{
var q = from c in context.X
select c;
return await q.ToListAsync();
}
But in the task I am awaiting the response by using result see below:
X = sm.FindXAsync().Result;
From my limited knowledge of using asynchronous programming with EF would each call run sequentially from inside the task?
Will the current set up return multiple return sets concurrently or would I have to create multiple tasks and await them separatly.
Again sorry for the vague question but i'm sure you guys are a lot more experienced on this topic than me ^^
Edit: I release there wasn't really a proper question in there, I guess what I am wondering is would x,y and z return concurrently or sequentially from within the task.
await Task.Run(() =>
{
x = sm.FindXAsync().Result;
y = new ObservableCollection<Y>(sm.FindYAsync().Result);
z = new ObservableCollection<Z>(sm.FindZAsync().Result);
}).ConfigureAwait(False)
Thanks,
Chris
Yes, the will run sequentially when you use the Result property. Also they will run sequentially with the following code: `
x = await sm.FindXAsync().ConfigureAwait(False);
y = new ObservableCollection<Y>( await sm.FindYAsync().ConfigureAwait(False));
z = new ObservableCollection<Z>(await sm.FindZAsync().ConfigureAwait(False));
Also update
public async void LoadData to return Task -> `public async Task LoadData`.
If you want to run all code in parallel add the taks in an array and then call await Task.WhenAll(tasks)
I have a list of objects that I need to run a long running process on and I would like to kick them off asynchronously, then when they are all finished return them as a list to the calling method. I've been trying different methods that I have found, however it appears that the processes are still running synchronously in the order that they are in the list. So I am sure that I am missing something in the process of how to execute a list of tasks.
Here is my code:
public async Task<List<ShipmentOverview>> GetShipmentByStatus(ShipmentFilterModel filter)
{
if (string.IsNullOrEmpty(filter.Status))
{
throw new InvalidShipmentStatusException(filter.Status);
}
var lookups = GetLookups(false, Brownells.ConsolidatedShipping.Constants.ShipmentStatusType);
var lookup = lookups.SingleOrDefault(sd => sd.Name.ToLower() == filter.Status.ToLower());
if (lookup != null)
{
filter.StatusId = lookup.Id;
var shipments = Shipments.GetShipments(filter);
var tasks = shipments.Select(async model => await GetOverview(model)).ToList();
ShipmentOverview[] finishedTask = await Task.WhenAll(tasks);
return finishedTask.ToList();
}
else
{
throw new InvalidShipmentStatusException(filter.Status);
}
}
private async Task<ShipmentOverview> GetOverview(ShipmentModel model)
{
String version;
var user = AuthContext.GetUserSecurityModel(Identity.Token, out version) as UserSecurityModel;
var profile = AuthContext.GetProfileSecurityModel(user.Profiles.First());
var overview = new ShipmentOverview
{
Id = model.Id,
CanView = true,
CanClose = profile.HasFeatureAction("Shipments", "Close", "POST"),
CanClear = profile.HasFeatureAction("Shipments", "Clear", "POST"),
CanEdit = profile.HasFeatureAction("Shipments", "Get", "PUT"),
ShipmentNumber = model.ShipmentNumber.ToString(),
ShipmentName = model.Name,
};
var parcels = Shipments.GetParcelsInShipment(model.Id);
overview.NumberParcels = parcels.Count;
var orders = parcels.Select(s => WareHouseClient.GetOrderNumberFromParcelId(s.ParcelNumber)).ToList();
overview.NumberOrders = orders.Distinct().Count();
//check validations
var vals = Shipments.GetShipmentValidations(model.Id);
if (model.ValidationTypeId == Constants.OrderValidationType)
{
if (vals.Count > 0)
{
overview.NumberOrdersTotal = vals.Count();
overview.NumberParcelsTotal = vals.Sum(s => WareHouseClient.GetParcelsPerOrder(s.ValidateReference));
}
}
return overview;
}
It looks like you're using asynchronous methods while you really want threads.
Asynchronous methods yield control back to the calling method when an async method is called, then wait until the methods has completed on the await. You can see how it works here.
Basically, the only usefulness of async/await methods is not to lock the UI, so that it stays responsive.
If you want to fire multiple processings in parallel, you will want to use threads, like such:
using System.Threading.Tasks;
public void MainMethod() {
// Parallel.ForEach will automagically run the "right" number of threads in parallel
Parallel.ForEach(shipments, shipment => ProcessShipment(shipment));
// do something when all shipments have been processed
}
public void ProcessShipment(Shipment shipment) { ... }
Marking the method as async doesn't auto-magically make it execute in parallel. Since you're not using await at all, it will in fact execute completely synchronously as if it wasn't async. You might have read somewhere that async makes functions execute asynchronously, but this simply isn't true - forget it. The only thing it does is build a state machine to handle task continuations for you when you use await and actually build all the code to manage those tasks and their error handling.
If your code is mostly I/O bound, use the asynchronous APIs with await to make sure the methods actually execute in parallel. If they are CPU bound, a Task.Run (or Parallel.ForEach) will work best.
Also, there's no point in doing .Select(async model => await GetOverview(model). It's almost equivalent to .Select(model => GetOverview(model). In any case, since the method actually doesn't return an asynchronous task, it will be executed while doing the Select, long before you get to the Task.WhenAll.
Given this, even the GetShipmentByStatus's async is pretty much useless - you only use await to await the Task.WhenAll, but since all the tasks are already completed by that point, it will simply complete synchronously.
If your tasks are CPU bound and not I/O bound, then here is the pattern I believe you're looking for:
static void Main(string[] args) {
Task firstStepTask = Task.Run(() => firstStep());
Task secondStepTask = Task.Run(() => secondStep());
//...
Task finalStepTask = Task.Factory.ContinueWhenAll(
new Task[] { step1Task, step2Task }, //more if more than two steps...
(previousTasks) => finalStep());
finalStepTask.Wait();
}