|
Kevin Marois wrote: What's a 'closure'?
When an anonymous function / lambda method references local variables, those variables are hoisted into a compiler-generated class called a closure.
Given:
public void Foo()
{
List<ProjectHeaderEntity> projects = null;
await Task.Run(() => { projects = AppCore.BizObject.GetProjectHeaders(AppCore.AppCompany.Id).ToList(); });
Console.WriteLine(projects.Count);
} the compiler will generate something closer to:
private sealed class <>_SomeRandomGeneratedName
{
public List<ProjectHeaderEntity> projects;
public Action TheAction;
public void TheActualMethod()
{
this.projects = AppCore.BizObject.GetProjectHeaders(AppCore.AppCompany.Id).ToList();
}
}
public void Foo()
{
var closure = new <>_SomeRandomGeneratedName();
closure.TheAction = new Action(closure.TheActualMethod);
await Task.Run(closure.TheAction);
Console.WriteLine(closure.projects.Count);
}
By changing the code so that it no longer refers to the local variables, you can get rid of the closure class:
public void Foo()
{
List<ProjectHeaderEntity> projects = await Task.Run(() => AppCore.BizObject.GetProjectHeaders(AppCore.AppCompany.Id).ToList());
Console.WriteLine(projects.Count);
} should compile to something like:
private static Func<List<ProjectHeaderItem>> TheCachedDelegate;
private static List<ProjectHeaderEntity> TheActualMethod()
{
return AppCore.BizObject.GetProjectHeaders(AppCore.AppCompany.Id).ToList();
}
public void Foo()
{
if (TheCachedDelegate == null)
{
TheCachedDelegate = new Func<List<ProjectHeaderItem>>(TheActualMethod);
}
List<ProjectHeaderEntity> projects = await Task.Run(TheCachedDelegate);
Console.WriteLine(projects.Count);
} which has significantly fewer allocations, particularly when called multiple times.
Kevin Marois wrote: I thought that WITHOUT WhenAll, the first would run, then the other one.
The task starts running as soon as you call Task.Run . Your code waits for the task to complete when you await it. If you separate the two, you can do other things in between the task starting and waiting for the task to complete, including starting other tasks.
await Task.Run(() => ...);
await Task.Run(() => ...);
DoSomething();
Task a = Task.Run(() => ...);
Task b = Task.Run(() => ...);
await a;
await b;
DoSomething();
Task a = Task.Run(() => ...);
Task b = Task.Run(() => ...);
await Task.WhenAll(new[] { a, b });
DoSomething();
You generally need Task.WhenAll when you have an unknown number of tasks to wait for. With two tasks, where you want the return value, and they are returning different types, it's easier to just await each in turn. If you used Task.WhenAll , you'd either have to await the tasks again, or use their Result property, to get the return value from each.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Wow, great info. I just learn some new things!
Thanks a bunch
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
In your response in the part about WhenAll, you say they are all running already, then the first waits, then the second waits.
I asked about WhenAll because I watched this video where at around 22:30 he converts a loop that runs tasks one at a time, to creating a List<task> and using WhenAll to wait for them all to finish. He said that they would all execute at the same time and therefore incrase performance a bit. So I figured that since I neeed BOTH calls to be done before I continued, why wait for one, then the other.
I'm asking because as I mentioned before I'm converting a synchronous WPF app to target an API, and in this app there are all kinds of backend calls grouped together, with each one calling the BL => DAL for some piece of data.
For example, the LoadJob method on the Job View makes multiple calls one after another to the backend for mutiple pieces of data when it's being loaded, and it's getting progressively slower. This view has an upper detail section, and subtabs below. Right now ALL of the data for the details AND all the tabs is retrieived using individual backend calls. I'm going to have the detail section load async on opening, then the subtabs will be lazy loaded. But again, there's a whole bunch of calls, so I thought if I used WhenAll, I could get parallel loading and reduce the drag on the system.
I'm curious about your thoughts on this.
Thank you.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 15-Oct-21 14:43pm.
|
|
|
|
|
If you have a large or unknown number of tasks, or you don't care about the value (if any) returned by the tasks, then Task.WhenAll is usually the simplest option. But it's not required to get multiple tasks running at the same time.
If you're just loading data and setting the properties on your view-models, you generally don't need to be running on the UI thread. If you're updating a collection, you might need to use BindingOperations.EnableCollectionSynchronization[^] to enable updates from a background thread; but most property changes on a view-model will just work from any thread.
But as you discovered, you will need to be running on the UI thread to show another view. Therefore, you probably want to split the job into multiple tasks: a top-level task which kicks off the loading tasks, awaits Task.WhenAll to wait for them to finish (without using ConfigureAwait ), and then displays the dialog; and multiple sub-tasks which load the data and update the view-model, which can use .ConfigureAwait(false) .
Eg:
private async Task LoadProjects(VendorsByProjectAndJobReportViewModel vm)
{
var projects = await Task.Run(() => AppCore.BizObject.GetProjectHeaders(AppCore.AppCompany.Id).ToList()).ConfigureAwait(false);
vm.Projects = projects;
}
private async Task LoadJobs(VendorsByProjectAndJobReportViewModel vm)
{
var jobs = await Task.Run(() => AppCore.BizObject.GetJobListHeaders(AppCore.AppCompany.Id).ToList()).ConfigureAwait(false);
vm.Jobs = jobs;
}
private async Task ShowVendorsByProjectAndJobReport()
{
WaitIndicatorVisibility = Visibility.Visible;
var dialogVm = new VendorsByProjectAndJobReportViewModel();
var tasks = new List<Task>
{
LoadProjects(dialogVm),
LoadJobs(dialogVm),
};
await Task.WhenAll(tasks);
DialogResultEx result = DialogService.ShowDialog(dialogVm, typeof(MainWindowView));
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Wow, that's great. I really appreciate your help. Thanks!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I have the following code which runs on VS code but not when I try to compile on codility:
using System;
static class Solution {
static int solution( int[] A ) {
int flag = 1;
Array.Sort(A);
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= 0)
continue;
else if (A[i] == flag)
{
flag++;
}
}
return flag;
}
static void Main(string[] args) {
int[] A = { 1, 3, 6, 4, 1, 2 };
if(A.Length<99999)
{
int miss = solution(A);
Console.Write(miss);
}
else
{
Console.WriteLine(" Array is too large! ");
}
}
}
The error I get is :
Compiler output:
Compilation failed: 2 error(s), 0 warnings
exec.cs(18,24): error CS0017: Program `exec.exe' has more than one entry point defined: `SolutionWrapper.Main(string[])'
Solution.cs(23,17): error CS0017: Program `exec.exe' has more than one entry point defined: `Solution.Main(string[])'
Runs just fine in VS code but not on codility, anyone know why?
modified 13-Oct-21 16:02pm.
|
|
|
|
|
Maybe the Codility whatever-it-is supplies an enclosing Main method, making your Main method a duplicate ? Try removing your Main method.
Obviously, the place to ask about this is: [^].
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Hello, newbee question
How do I pass an array to a function? Below is my code, the error i get is Quote: The local function 'Main' is declared but never used
<pre lang="C#"><pre>using System;
using System.Linq;
static int solution(int[] A) {
int maxSize = 100000;
int[] counter = new int[maxSize];
foreach (var number in A)
{
if(number >0 && number <= maxSize)
{
counter[number - 1] = 1;
}
}
for (int i = 0; i < maxSize; i++)
{
if (counter[i] == 0)
return i + 1;
}
return maxSize + 1;
static void Main(string[] args) {
int[] A = { 5, 9, 2, 7 };
Console.WriteLine(solution(A));
}
}
|
|
|
|
|
Your code is a complete mess. You have declared your methods outside of a class, which is not allowed. And you have declared your Main function inside the solution function.
Your code should look something like:
using System;
using System.Linq;
static class Program
{
static int solution(int[] A)
{
...
return maxSize + 1;
}
static void Main(string[] args)
{
int[] A = { 5, 9, 2, 7 };
Console.WriteLine(solution(A));
}
}
You need to follow a basic tutorial to learn C# - for example:
Introduction to C# - interactive tutorials | Microsoft Docs[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Aha, thanks for taking the time to answer a newbie question, works fine! A lesson learnt! Cheers!
|
|
|
|
|
I'm following up on my previous async question.
There are a TON of examples out there about how to consume an Async method, yet none of then actually show you what an async method signature looks like. For example, you see plenty of Entity Framework calls like
public async Task<List<Contact>> GetContactsAsync()
{
return await this.dbContext.Contacts.ToListAsync();
}
but how is ToListAsync actually defined? I'm assuming it returns a Task<list<t>>.
I came across this article, where it appears that all I need to do is return Task.FromResult<t>. Based on that, is this correct?
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Calling Test()");
Test();
Console.WriteLine("After Test");
Console.ReadLine();
}
private async static void Test()
{
Console.WriteLine("Calling GetSomeData()");
var results = await GetSomeData();
Console.WriteLine($"Results: {results}");
}
private static Task GetSomeData()
{
int x = 0;
for (; x (x);
}
Thread.Sleep(5000);
return Task.FromResult(x);
}
When I run this, it does not appear to run async. The console output is:
Calling Test()
Calling GetSomeData()
Results: 900000000
After Test
with a long pause at the call to GetSomeData(). I expected the Test method to return right away, and then, when GetSomeData completes, I would see the results.
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 7-Oct-21 17:25pm.
|
|
|
|
|
The article you linked to is a poor example - it shows how to wrap a synchronous result in a Task<T> , not how to implement an asynchronous method. That's usually not a sensible thing to do:
Should I expose asynchronous wrappers for synchronous methods? - .NET Parallel Programming[^]
Your code has been mangled, and also has several severe problems. For a start: Avoid async void methods[^]
Try:
static async Task Main()
{
Console.WriteLine("Calling Test()");
Task t = Test();
Console.WriteLine("After Test");
await t;
}
private static async Task Test()
{
Console.WriteLine("Calling GetSomeData()");
var results = await GetSomeData();
Console.WriteLine($"Results: {results}");
}
private static async Task<int> GetSomeData()
{
int x = 0;
for (; x < 9000; x++)
{
await Task.Delay(5);
}
return x;
} Output:
Calling Test()
Calling GetSomeData()
After Test
{delay}
Results: 9000
NB: If you're waiting for five seconds on every iteration of 900,000,000 loops, you'll have to wait roughly 142 years for your code to finish.
Waiting five seconds for every iteration of 9,000 loops would take 12½ hours to finish.
Reducing it to five milliseconds for 9,000 loops should technically let the code complete in 45 seconds. However, due to the Windows timer resolution it will almost certainly take longer.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
OK, so Making Test return Task was the issue?
You're right, my posting was messed up. The GetSomeData method really looked like this:
private static Task<int> GetSomeData()
{
int x = 0;
for (; x < 900000000; x++)
{
}
Thread.Sleep(5000);
return Task.FromResult<int>(x);
}
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
That method isn't async ; it blocks the caller, and then returns a result wrapped in a Task<T> instance.
If you make it async , you can use await Task.Delay(5000); instead of Thread.Sleep(5000); , and the caller will be able to continue after the loop has finished.
To let the caller continue before the loop has finished, you'd need to yield control before starting the loop.
private static async Task<int> GetSomeData()
{
await Task.Yield();
int x = 0;
for (; x < 900_000_000; x++)
{
}
await Task.Delay(5000);
return x;
}
A Tour of Task, Part 10: Promise Tasks[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
GOt it. Thanks!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Richard Deeming wrote: o let the caller continue before the loop has finished, you'd need to yield control before starting the loop.
Wouldn't you want to do this all the time?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
No, why would you? Just makes the processor waste time switching between things slowing down everything. It will not even start a new thread, just make the called code wait, instead of the caller.
An important thing to know is: Async/await is NOT concurrent programming. I will not start any new threads - it will not cause anything to be processed at the same time... only the method you call with an "await" can start work in parallel (by scheduling IO to complete on the IO completion threads, thread pool, it's own thread, or responding to events from other parts of the code potentially running on a different thread).
Sure, it can be used along with concurrency - and the way it is implemented can result in you running code concurrently that you did not expect - but that is a side effect and one of the things that makes async programming so hard.
Async on the server is not "invented to make the programmers life much easier". It is invented to get extra performance out of servers as they will waste less time context switching. It has been available for many many years (decades), but was horrible to program. Now we have async/await it is no longer horrible... just difficult. This is something you will notice as soon as you leave the safe path of demo applications.
|
|
|
|
|
Thanks for all the info. I appreciate it.
The reason I'm exploring this is because I'm working on a WPF app that calls SQL on my client's in-house server. Until now it's been a typcial synchronius, client-server model.
But now I'm going to be adding in a Xamarin Forms or .Net Maui app that allows my client to do work in the field. This means creating a web api and making calls async.
So, I'm trying to understand how to write both the back end and front end methods so that I don't hang the UI.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
As mentioned by others - do not worry about the server side being async. The web host will simply spin up more threads to handle the calls concurrently - and the client software will not be able to detect if you use async or not on the server.
Sure there is a limit to how many threads you can have running - but most likely the SQL server will give up before your web server. If not, then it is some serious heavy processing you are running - and either you should let someone more experienced deal with it or just run more servers. Typically you would run two servers anyway if high availability is required.
Just to be clear: You do not have to start threads yourself for the web server to run requests concurrently. The web server will do that for you.
If you do not need to get every bit of performance out of the server, the main advantage in using async on the server side is that all modern libraries expect it - and some might no longer have sync method calls available. So if you write your code async, you will never have sync code calling async methods. Sure it can be done if needed, but you need to know what you are doing to avoid deadlocks. Async code calling sync methods is never an issue.
|
|
|
|
|
SEE AND CONTINUE DISCUSSION on the WPF Forum
I have a UI with a scrollviewer like this:
I want to scroll the viewer to the top when the ItemSource changes.
<ScrollViewer x:Name="Scroller" Grid.Row="2" Margin="0,0">
<StackPanel>
<ItemsControl x:Name="containers"
ItemsSource="{Binding Whatever, NotifyOnTargetUpdated=True}"
TargetUpdated="Containers_OnTargetUpdated">
</ItemsControl>
<StackPanel>
<ScrollViewer>
public partial class MyPage: UserControl
{
public MyPage()
{
InitializeComponent();
}
private void Containers_OnTargetUpdated(object? Sender, DataTransferEventArgs E)
{
var MyScroller = (ScrollViewer) this.FindName("Scroller");
MyScroller.ScrollToHome();
}
}
This works but it's probably not the best way to do it (ie. finding a control by name).
Can I pass the ScrollViewer "object" to the TargetUpdated callback/event ? so that I don't have to referencing it by name?
It seems clunky.
I don't know exactly what magic incantations I need to google for.
CI/CD = Continuous Impediment/Continuous Despair
modified 8-Oct-21 9:03am.
|
|
|
|
|
You could try the WPF forum.
|
|
|
|
|
(obviously, I should have seen that forum)
thanks.
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
The sender parameter should be the ItemsControl , in which case you just need to walk up the visual tree to find the ScrollViewer .
private void Containers_OnTargetUpdated(object? sender, DataTransferEventArgs e)
{
var current = sender as DependencyObject;
var scroller = current as ScrollViewer;
while (scroller == null && current != null)
{
current = VisualTreeHelper.GetParent(current);
scroller = current as ScrollViewer;
}
if (scroller != null)
{
scroller.ScrollToHome();
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks, it works.
(sorry if I did not answer before).
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
Hello fellow members. Im trying to understand why my code is not catching NullReferenceException and i cant figure it out.
I'm using this code to run async function
private async Task SearchMostLessViewsAsync(DateTime dateFrom, DateTime dateTo, int amountOfNumbersSelected, int frequencyOption, int fromDrawNumber, int toDrawNumber)
{
Microsoft.AppCenter.Analytics.Analytics.TrackEvent($"{typeof(FragmentDrawsNumbersFrequency).Name}.{nameof(SearchMostLessViewsAsync)}",
new Dictionary<string, string>()
{
{nameof(dateFrom), dateFrom.ToString()},
{nameof(dateTo), dateTo.ToString()},
{nameof(amountOfNumbersSelected), amountOfNumbersSelected.ToString()},
{nameof(frequencyOption), frequencyOption.ToString()},
{nameof(fromDrawNumber), fromDrawNumber.ToString()},
{nameof(toDrawNumber), toDrawNumber.ToString()},
}
);
((MainActivity)Activity).DisplayLoadingMessage(true, GetString(Resource.String.Common_SearchTitle),
GetString(Resource.String.Common_SearchMessage));
var task = Task.Run(async () =>
{
var textResult = await SearchLeast(dateFrom, dateTo, amountOfNumbersSelected, frequencyOption, fromDrawNumber, toDrawNumber).ConfigureAwait(false);
if (!string.IsNullOrEmpty(textResult))
{
UpdateHistoryList(textResult);
DatabaseFunctions.SaveHistoryList(HistoryList, Settings.DrawsNumbersFrequencyHistoryListViewKey);
((MainActivity)Activity).ShowSearchResults(textResult);
}
}, ApplicationState.GetCancellationToken());
try
{
await task.ConfigureAwait(false);
}
catch (TaskCanceledException tce)
{
Console.WriteLine($"{nameof(TaskCanceledException)} thrown with message: {tce.Message}");
}
catch (System.ObjectDisposedException ode)
{
Console.WriteLine($"{nameof(System.ObjectDisposedException)} thrown with message: {ode.Message}");
}
catch (System.OperationCanceledException e)
{
Console.WriteLine($"{nameof(System.OperationCanceledException)} thrown with message: {e.Message}");
}
catch (NullReferenceException nre)
{
Console.WriteLine($"{nameof(NullReferenceException)} thrown with message: {nre.Message}");
}
finally
{
ApplicationState.DisposeCancellationTokenSource();
((MainActivity)Activity).DisplayLoadingMessage(false);
}
((MainActivity)Activity).DisplayLoadingMessage(false);
}
But sometimes i get this exception
FragmentDrawsNumbersFrequency.SearchMostLessViewsAsync (System.DateTime dateFrom, System.DateTime dateTo, System.Int32 amountOfNumbersSelected, System.Int32 frequencyOption, System.Int32 fromDrawNumber, System.Int32 toDrawNumber)
FragmentDrawsNumbersFrequency.ShowMostLessViews ()
FragmentDrawsNumbersFrequency.<OnCreateView>b__50_8 (System.Object sender, System.EventArgs e)
AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_0 (System.Object state)
SyncContext+<>c__DisplayClass2_0.<Post>b__0 ()
Thread+RunnableImplementor.Run ()
IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this)
(wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.61(intptr,intptr)
I'm not sure why. Shouldn't the try catch wrap catch nullreference exceptions? Something tells me i miss something else here
modified 2-Oct-21 8:56am.
|
|
|
|
|