I am targeting WPF .NET 4.6.1.
I am constantly doing this:
btnClick
{
Task T1 = Task.Run<List<Double>>( AsyncFunction );
T1.Wait(.1);
Dispatcher.Invoke(() => { txtStatus.Text+="HOLD ON.."; };
T1.Wait(.1);
}
The only way I can get this to actually update the UI between these Wait(s) is to do:
Dispatcher.Invoke(new Action(()=>{}),priority: DispatcherPriority.ApplicationIdle);
Is this right? Is this portable? Describe discuss different approaches on different platforms (UWP, Windows 10 Phone).
Possibly see Raymond Chen: https://devblogs.microsoft.com/oldnewthing/20190327-00/?p=102364
I explicity do not want to use Async Button Event because I need to be able to help the user, at least put logic for a tenth of a second completion check and not have the user slamming the async button handler trying to get results and congesting my sensor network with data.
You know I eventually want to get the result of this too, and process it, IN THE SAME EVENT HANDLER CODE, so like I don't want to use BackroundWorker and then have the user have to Click another button to poll the Results, which may STILL BE EMPTY and make everybody REALLY REALLY MAD. And I don't want to Poll the results automatically and then poll the sensors network again and cause MORE congestion.
I explicity do not want to use Async Button Event because I need to be able to help the user, at least put logic for a tenth of a second completion check and not have the user slamming the async button handler trying to get results and congesting my sensor network with data.
The easiest solution is to do it the way everyone else solves it: disable the button while the operation is in progress.
async btnClick
{
btn.Enabled = false;
try
{
txtStatus.Text += "HOLD ON..";
var result = await Task.Run(() => AsyncFunction());
... // update UI with result.
}
finally { btn.Enabled = true; }
}
As an interim update, my testing indicates that both async event handlers and small synchronous Wait(s) are both appropriate approaches. I am achieving significantly better initial response by delegating only Wait(.1) to the network operation, initiating a DispatcherInvoke(()=>{txtStatus+="WAIT.."} and immediately followed by Dispatch(() =>{;//}, DispatcherPriority.ApplicationIdle).
Using an async event handler, and IProgress (you don't even need Dispatcher, just alter a bound control) inside the network call results in similar progress update, but with an initial response that may not be acceptable.
Using the synchronous waits results in a stalling of the UI Paint that makes any gradually updating progress bar appear very jerky.
For me, the progress bar being jerky is not the issues, because I am giving the operator direct feedback with WAIT.. WAIT .. WAIT ..And all the progress bar is doing is showing, by stalling, how backed up the thing is, but I retain enough synchronous control to jam an oscillating CAUTION in there. The oscillation may be jerky but trained operators will know, if that CAUTION keeps toggling, however unevenly, you are on, even if the gradual progress bar stalls and starts.
And, I can detect this in synchronous code, and then do something about it on the fly, like, offload the whole network call and then force the user to queue and poll.
UPDATE
async Task<List<Double>> NetworkList(IProgress<Int32> NetworkProgress)
{
List<Double> _results = new List<Double>();
foreach(var aNetwork in LotsOfNetworksCouldTakeAwhile)
{
SendPingFarAwayLand();
await Task.Delay(delay: TimeSpan.Frommilliseconds(100);
Double PingTime = GetPingTimeOrNull();
_results.Add(PingTIme);
NetworkProgress.Report( aNetwork.NetworkID );
}
}
async btnClick
{
TimeSpan IDLE_LONG_ENOUGH_SO_DISPATCHER_UPDATES_UI = TimeSpan.FromMilliseconds(50);
txtStatus += "WORKING...";
await Task.Delay(delay: IDLE_LONG_ENOUGH_SO_DISPATCHER_UPDATES_UI);
Task<List<Double>> results = await NetworkList(_Progress);
dependencyObject1.ObservableList1.Add(results);
return;
}
This seems to work at least on my computer. About 50 millis is enough to guarantee the dispatcher processes your latest "WORKING..." message immediately. If you don't, you may hit the dispatcher on an up cycle, but maybe not, and it will start on LongNetworkList and it may be a half second before you even see that something is happening.
It's almost like do you want the sprint team captain to hit the stopwatch, or run with you. Delay of 50 millis to even start on the work seems like a lot if you are trying to ping two sub 10ms networks. But if you have even one aberrant one in there that immediately takes up the whole 100ms await and STILL doesn't return anything for you to report progress on, it's nice to have put up something on the screen.
Kudos to Cleary, I'm switching to Reactive.NET, right after lunch.
Related
Hi I am now trying to create a simple dApp to learn Solidity and interaction with it.
I am wondering which is a better way for listening events from smart contracts and applying state changes from transactions to the front end, using on method from Contract instance or wait from TransactionResponse.
I am using ethers.js, and it gives you something like this to listen events from smart contracts:
const myContract = new Contract(address, abi, provider);
myContract.on("eventName", (...args) => { // do something here}
Also calling the transaction method from the contract instance like the above, it returns Promise<ethers.ContractTransaction> type.
The returned object has wait method and it waits until the transaction has been mined like below:
myContract.someFunction(...args).then(async (response: ContractTransaction) => {
await response.wait();
// do something after transaction has been mined
}
**ContractTransaction is extended from TransactionResponse
Considering two ways to handle values after transactions have been mined, is one better the other?
Or is there even another way better than these?
I would imagine "better" depends on how I structure components (I am using React) and other things.
But I would like to know your preference at least :)
Thanks!
The first one would be better because it will passively listen for changes and update when they happen. With the 2nd one, you have to stop the execution of the function and whatever else you're doing in order to display something after the transaction happens. This means you'd have to set up some sort of loading page, but if the user leaves before the transaction is mined then what you will be waiting for is lost.
I'm wondering if there is some technique or method to detect calls in a WPF app that are not using async/await.
The reason I ask is that the WPF app I am working on is stuttering and halting on the screen updates, and I can't seem to track down the source of the calls that are blocking the GUI thread.
I am using VS2012 and VS2013 with the MVVM design pattern.
This doesn't answer your question directly but this will help with identifying when the dispatcher thread is overloaded, the following code uses an event handler around the DispatcherInactive event to calculate how long dispatcher thread has been overloaded (blocked) with work:
var maxThreshold = TimeSpan.FromMilliseconds(750);
var previous = DateTime.Now;
Application.Current.MainWindow
.Dispatcher.Hooks.DispatcherInactive += (sender, eventArgs) =>
{
var current = DateTime.Now;
var delta = current - previous;
previous = current;
if (delta > maxThreshold)
{
Debug.WriteLine("UI Freeze = {0} ms", delta.TotalMilliseconds);
}
};
I would suggest this is only ever used in debug mode, so it would be wrapped in a #if DEBUG block. You don't want this running in production.
I think a performance profiler could help you in this case.
I personally recommend ANTS profiler, you can download a trial and test your application with it. It would tell you where a certain period of the execution of your app is spending its time in.
Usually it is very easy to find what is blocking the UI. There can be 2 cases - either you are performing an expensive operation on the UI thread, you can test if the thread executing is the UI thread using:
if (Thread.CurrentThread == Dispatcher.CurrentDispatcher.Thread)
{
//UI Thread
}
Or, you are displaying to many controls and it takes long time to render. Usually the lists cause this when the list is not virtualizing items.
You can subscribe to events of the WPF dispatcher to track down your problem. The UI thread queues work items inside an object called a Dispatcher. The Dispatcher selects work items on a priority basis and runs each one to completion.
To monitor the Dispatcher you can e.g. subscribe to these operations:
Dispatcher.Hooks.OperationPosted += Hooks_OperationPosted;
Dispatcher.Hooks.OperationStarted += Hooks_OperationStarted;
Dispatcher.Hooks.OperationAborted += Hooks_OperationAborted;
You find a full list here.
Depending on your problem you might find yourself better of with a commercial profiler but quite often you get good results with just observing the dispatcher queue.
My scenario. A page of my WP8 Silverlight app contains a ListBox control with the ability of item multiselection. When the user tap an item to toggle its selection state, I should perform a long operation for all items which are selected by that moment (for example, run a query to filter by the currently selected items). The user can tap some items very quickly, and there is no need to run the query every time after each tap (especially taking into account the fact that the query can take 1-2 seconds). I need to run the query if the user does nothing say for 1 or 2 seconds.
What is the best, not resource consuming, way to implement in WP8? Perhaps, the platform provides us with a useful service for that?
I would expect an application that behaves in such a way to be loathed by the users of it. But if you must then you simply need to reset a timer every time something that you consider as "activity" within your app happens. Presumably this'll be some form of user interaction such as page navigation or interacting/tapping/editing content.
It's crude but it'll work. It'll also negatively impact the battery too. You have been warned.
For Other Alternative see Resetting Idle Detection Countdown in Windows Phone
Your case sounds like a good candidate for Reactive Extensions
The following example uses an observer of ListBox selection changed event, and then wait for 1.5 seconds until reporting an observation:
var itemsChanged = (from evt in Observable.FromEventPattern<SelectionChangedEventArgs>(MyList, "SelectionChanged")
select MyList.SelectedItems)
.Throttle(TimeSpan.FromSeconds(1.5));
itemsChanged.ObserveOnDispatcher()
.Subscribe(items =>
{
Debug.WriteLine("----------------");
foreach (var item in items)
{
Debug.WriteLine(item);
}
}
);
Here is one solution in your scenario. note it is just the pseudo code to convey my solution
private bool isLoadingData = false;
private bool newQueryQueued = false;
///code in your itemselectionchanged event handler
if(isLoadingData)
{
newQueryQueued = true;
//Do not execute your query.
}
else
{
//Execute your query and get the result.
//after the query result is completed, execute the following code.
isLoadingData = false;
if(newQueryQueued)
{
isLoadingData = true;
newQueryQueued = false;
//Execute your query and get the result.
}
}
in the above pseudo code the query is executed only when it is need. say if use has tapped 4 item during first execution. it will not execute resource queries, because the previous result is still pending. and once the result is received the code will see if the user has changed his selection or not if the selection is changed than execute the query again.
and for the second part
I need to run the query if the user does nothing say for 1 or 2 seconds.
you need to implement timer on page load for what ever the time you want(1 or 2 seconds) and dispose off the timer after its first time elapses.
Hope this helps
I've been analyzing a WPF application which basically fetch data from a server and display the data in the GUI.
This code is not mine, and the application has a problem related with slow response from the GUI, I'm trying to find the reason for that problem.
I want to share with you my idea of which the problem could be and I'll like to hear what do you think about it, whether it makes any sense or not.
To get the data from the server, the application is using 7 threads (this is done in this way mostly because of the application logic, so don't pay too much attention to why 7 and not just one...), now, each thread is created by calling a method, called CreateThreadForTask()
public void StartAllThreads()
{
this.CreateThreadForTask(Tasks.Task1);
this.CreateThreadForTask(Tasks.Task2);
this.CreateThreadForTask(Tasks.Task3);
this.CreateThreadForTask(Tasks.Task4);
this.CreateThreadForTask(Tasks.Task5);
this.CreateThreadForTask(Tasks.Task6);
this.CreateThreadForTask(Tasks.Task7);
}
public void CreateThreadForTask(Tasks task)
{
... // this part of the code is not important
//! Initialize and start timer
timer = null;
timer = new DispatcherTimer();
timer.Tick += new EventHandler(RunMainSyncForTask);
timer.Start();
}
public void RunMainSyncForTask(object s, EventArgs e)
{
int sec = int.Parse(AppSettings.GetSetting("syncInterval"));
timer.Interval = new TimeSpan(0, 0, sec);
//threadCaller is a background worker
threadCaller = InitializeThread();
threadCaller.DoWork += DoWorkEventHandler(StartSync);
threadCaller.RunWorkerAsync();
}
When I was debugging the code I noticed that all the threads are created using a DispatcherTimer; what I think is that the application is creating 7 DispatcherTimer's and is linking the Tick event of the timers with the RunMainSyncForTask() method, which inside, create a background worker that fetch the data from the server and save that data to a local database.
Now, this was taken from the MSDN
The DispatcherTimer is reevaluated at the top of every Dispatcher loop.
Timers are not guaranteed to execute exactly when the time interval occurs, but they are guaranteed to not execute before the time interval occurs. This is because DispatcherTimer operations are placed on the Dispatcher queue like other operations. When the DispatcherTimer operation executes is dependent on the other jobs in the queue and their priorities.
So, based on that I believe that the application is spamming threads every time a timer does a tick event, and this is done 7 times simultaneously; and all these operations, because of the DispatcherTimer nature, are being added to the Dispatcher queue, which makes the GUI response slow, due to the Dispatcher being busy.
Also, another problem with the application is that, when it runs, it takes about 90-95% of the CPU, I think that if my hypothesis is right, this could be also the cause of for this problem.
So if you can share some insides about this I'll appreciate it.
Thanks.
You're getting the 90-95% CPU because you've instituted a form of busy waiting through a crazy web of threading calls.
If you're using this StartSync logic to post status notifications or get data back to the GUI, you're jumping through a lot of hoops. If you're on .Net 4.0 you should switch to the Task Parallel Library and let the framework handle all of this for you. It also supports graceful cancellation, etc.
If you don't wish to use TPL, I would suggest instead passing the Windows Dispatcher (use the usual suspects: Invoke or BeginInvoke) or SynchronizationContext (asynchronously with Post, synchronously with Send) to the individual tasks for use for these tasks which must be done in the GUI.
In my WPF app I have a long running upload running, which raises progress events as it goes which updates a progress bar. The user also has a chance of cancelling the upload, or it might go wrong. These are all async events, so they need to be executed using Dispatcher.Invoke in order to update the UI.
So the code looks like this, ish:
void OnCancelButtonClicked(object sender, EventArgs e)
{
upload.Cancel();
_cancelled = true;
view.Close();
view.Dispose();
}
void OnProgressReceived(object sender, EventArgs<double> e)
{
Dispatcher.Invoke(() =>
{
if (!cancelled)
view.Progress = e.Value;
}
}
Supposing that setting view.Progress on a disposed view is going to throw an error, is this code thread safe? i.e. if a user clicks cancel while the progress is updating, he/she will have to wait until the progress has been updated, and if the progress is updated during execution of OnCancelButtonClicked, the Dispatcher.Invoke call will cause the view.Progress update to be queued til after _cancelled is set, so I won't get a problem there.
Or do I need a lock to be safe, a la:
object myLock = new object();
void OnCancelButtonClicked(object sender, EventArgs e)
{
lock(myLock)
{
upload.Cancel();
_cancelled = true;
view.Close();
view.Dispose();
}
}
void OnProgressReceived(object sender, EventArgs<double> e)
{
Dispatcher.Invoke(() =>
{
lock(myLock)
{
if (!cancelled)
view.Progress = e.Value;
}
}
}
You don't have to add a lock. Dispatcher.Invoke and BeginInvoke requests will not run in the middle of other code (that's the whole point of them).
Just two things to consider:
BeginInvoke may be more appropriate in this case, Invoke will queue the request and then block the calling thread until the UI thread becomes idle and finishes executing the code, BeginInvoke will only queue the request without blocking.
Some operations, especially operations that open windows (including message boxes) or do inter-process communication may allow the queued dispatcher operations to run.
EDIT: first, I don't have citations because the MSDN pages on the subject are unfortunately very low on details - but I have written test programs to check the behavior of BeginInvoke and everything I write here is the result of those tests.
Now, to expand on the second point we first need to understand what the dispatcher does. Obviously this is a very simplified explanation.
Any Windows UI works by processing messages; For example when the user moves the mouse over a window the system will send that window a WM_MOUSEMOVE message.
The system send the message by adding it a queue, each thread may have a queue, all windows created by the same thread share the same queue.
In the heart of every Windows program there's a loop called "message loop" or "message pump", this loop reads the next message from the queue and calls the appropriate window's code to process that message.
In WPF this loop and all the related processing handled by the Dispatcher.
An application can either be in the message loop waiting for the next message or it could be doing something. That is why when you have a long calculation all the thread's windows become unresponsive - the thread is busy working and doesn't return to the message loop to process the next message.
Dispatcher.Invoke and BeginInvoke works by queuing the requested operation and executing it the next time the thread returns to the message loop.
That is why Dispatcher.(Begin)Invoke can't "inject" code in the middle of your method, you won't get back to the message loop until your method returns.
BUT
Any code can run a message loop. When you call anything that runs a message loop the Dispatcher will be called and can run the (Begin)Invoke operations.
What kinds of code has a message loop?
Anything that has a GUI or that accepts user input, for example dialog boxes, message boxes, drag&drop etc. - if those didn't have a message loop then the app would have been unresponsive and unable to handle user input.
Inter-process communication that uses windows messages behind the scenes (most inter-process communication methods, including COM, use them).
Anything else that takes a long time and doesn't freeze the system (the fast that the system isn't frozen is proof it's processing messages).
So, to summarize:
the Dispatcher can't just drop code into your thread, it can only execute code when the application is in the "message loop".
Any code you write doesn't have message loops unless you explicitly wrote them.
Most UI code doesn't have it's own message loop, for example if you call Window.Show and then do some long calculation the window will only appear after the calculation is finished and the method returns (and the app returns to the message loop and processes all the messages required to open and draw a window).
But any code that interacts with the user before it returns (MessageBox.Show, Window.ShowDialog) has to have a message loop.
Some communication code (network and inter-process) uses message loops, some doesn't, depending on the specific implementation you are using.
This is an interesting question. Items executed in the dispatcher are queued and execute on the same thread as UI interaction. Here's the best article on this subject:
http://msdn.microsoft.com/en-us/library/ms741870.aspx
If I were to venture a guess, I would say that Dispatcher.Invoke(Action) probably queues an atomic work item, so it's likely going to be ok, however I'm not sure if it wraps up your UI event handler in an atomic action item for instance:
//Are these bits atomic? Not sure.
upload.Cancel();
_cancelled = true;
For safety's sake I would personally lock, but your question warrants more research. Might need a dive in reflector to figure out for sure.
As an aside, I'd probably optimize your lock a bit.
Dispatcher.Invoke(() =>
{
if (!cancelled)
{
lock(myLock)
{
if(!cancelled)
view.Progress = e.Value;
}
}
}
But that's probably overkill :)