I want to run a task which queries a database for new messages for a user.
I want the task to run every x seconds, in a new tread so it doesn't cause the UI to become unresponsive.
If the database task finds messages then i would want it to make these messages available to the UI.
I thought the whole loop would run in its own thread, rather than have a loop in the UI thread that keeps creating a new thread every x seconds. I thought that would stop multiple calls to the database e.g. if i set the lookup to every 5 seconds and the database took longer than 5 seconds to respond.
I've been looking for a good few hours - the best article i found was:
https://blogs.msdn.microsoft.com/benwilli/2016/06/30/asynchronous-infinite-loops-instead-of-timers/
I'm new to threading and the above link seems relatively simple in its last example DoWorkAsyncInfiniteLoop, however it seems to run on the UI thread (although it mentions you could then use Task.Run to make it run in its own thread, and i'm not sure how found messages would be available to the UI thread.
Any advice would be greatly appreciated!
Using SQLDependency you will no more need to add an infinite loop. see below link:
SQLDependency Using C#
by using a new thread in WindowsForm you cant directly access to UI Elements because they are in your main thread. in this Situation you must use Dispatchers, here is an explanation about it:
Access UI Element From Another Thread
OK had some minor difficulty - can't use a dispatcher as i am using MVVM and the view model doesn't have a dispatcher as it is not a derived from a UI base. Here is my final code for anyone else trying to achieve this
public MainViewModel() //the constructor for the viewmodel
{
_Repo = CurrentApp.MainController.RepositoryManager; // this is my database access methods
Task t = Task.Run(CheckMessagesAsyncInfiniteLoop); //run the new thread
}
private async Task CheckMessagesAsyncInfiniteLoop() //this is my infinite loop as described in the above link, but run from the above Task.Run
{
while (true)
{
// Check the messages in the database
Messages = _Repo.Service_Message_GetList(CurrentApp.CurrentUser.BasicInfo.UserID);
// pause for the next check
await Task.Delay(30000);
}
}
Repository.DomainLayer.MessageCollection _Messages; //the collection that will be updated by the thread above
public Repository.DomainLayer.MessageCollection Messages //the property that my view is bound to
{
get
{
return _Messages;
}
set
{
_Messages = value;
NotifyPropertyChanged();
}
}
Related
I developed a small client (WPF) to make some stress test on our systems. Essentially it has to call various methods on an Asp.Net WebApi endpoint in parallel.
Each time you press "Start" it generates 4000 tasks (Async - Await) in parallel with request to stress, waits until they all finish, then it does it again - until the user clicks the stop button. The GUI is decorated with a progress bar and some counters: requests in error, completed request, in progress requests. I obtain these informations because the object that makes the batch of stress requests exposes some events:
var stressTestTask = new stressTestTask(LogService, configuration);
stressTestTask.ErrorRequestCountChanged += stressTestTask_ErrorRequestCountChanged;
stressTestTask.GoodRequestCountChanged += stressTestTask_GoodRequestCountChanged;
stressTestTask.TryRequestCountChanged += stressTestTask_TryRequestCountChanged;
_executionCancellationToken = new CancellationTokenSource();
await Task.Run(
() => stressTestTask.ApiStressTestTask(_executionCancellationToken.Token),
_executionCancellationToken.Token);
The whole execution is started from an ICommand (MVVM):
private RelayCommand _startCommand;
public RelayCommand StartCommand
{
get
{
return _startCommand ?? (_startCommand = new RelayCommand(
async () =>
{
await StartStressTest();
}));
}
}
RelayCommand is an implementation of ICommand from the library Mvvm-Light.
What I don't understand is this behaviour: if I configure my batch of tasks with a "low" number of tasks, for example 2000, the GUI doesn't freeze while executing. If instead I choose 5000 tasks, after a while it freezes. If then I open another instance of the .exe of my client and I choose 2000 on each, the GUI is responsive in both.
My first question is: why opening one instance with x tasks is worse in terms of responsivness than opening n instances with x/n tasks? Is it something related to Windows Scheduler and the fact that in the first case I have only one process?
My second questions is: how can I address the problem to make everything work on a single GUI? I thought about making a console application with the single batch of stress tests and calling a command from the GUI for each instance I want, in order to generate a process for every batch.
Are you handling those API events by invoking to the UI context? If you have many invocations occurring you will flood the dispatcher with operations and cause the UI to hang and lag behind user input.
Try batching the UI updates.
My first question is: why opening one instance with x tasks is worse in terms of responsivness than opening n instances with x/n tasks?
Possibly because you are getting more events to handle on the UI thread. I guess your ErrorBetCountChanged, GoodRequestCountChanged and TryRequestCountChanged event handlers are invoked on the UI thread and a lot of events being raised may flood the UI thread.
As Gusdor suggets you should probably find a way of batching the updates. Take a look at the reactive extensions (Rx): http://www.introtorx.com/content/v1.0.10621.0/01_WhyRx.html.
It has a Buffer method that may come in handy: http://www.introtorx.com/content/v1.0.10621.0/13_TimeShiftedSequences.html.
It also has en Obervable.FromEvent method that you can use to convert an event into an IObservable: https://msdn.microsoft.com/en-us/library/hh229241(v=vs.103).aspx.
My second questions is: how can I address the problem to make everything work on a single GUI?
You need to find a way - one or anoher - of updating the UI less frequently. Batching the updates and events should be a good starting point. Raising less notifications is another option. Maybe you need to both.
how can I address the problem to make everything work on a single GUI?
Send API requests in "proper" async-await manner with only one thread.
private async Task SendStressRequests()
{
var tasks = new List<Task>();
for (int i = 0; i < 4000; i++)
{
var task = SendApiRequestAsync();
tasks.Add(task);
}
await Task.WhenAll(tasks);
// Update UI with results
}
I have a question about solving UI freezing.
Introduction:
I am currently programming an OPC based online alarm reader for a given analyzer tool. This tool received data from an excel sheet, analyzed this data using a rule base and a topology model and shows the results with TreeViewItems.
My task is to replace the excel sheet reader by a real time alarm reader.
That's done, I can connect my software to server and receive data packages every time new alarms are created.
Problem:
My solution for transport the new data to the main class and from there to the analyzer class is saving the data in a list, adding them to an EventArgs and raising an Event. The handling method in the main class receives this data, starts a new task (Task>) for the analyzer and returns its results to the Main Thread.
This construction should have uncoupled the calculation process from the UI The analyzing process takes about 1.3s with example data. New data arrives every 2 seconds on average. 2 seconds is in the same time the highest refreshing time.
Attached is a code snippet from the handling method
Task<List<Analyser.ALARM_GROUP>> analysertask = Task.Factory.StartNew<List<Analyser.ALARM_GROUP>>(
()=>
{
/*if the alarmlist is emty, set the new alarms as alarmlist,
* else add the new alarms to the present list*/
if (AlarmList1.Count == 0)
AlarmList1 = e.CurrentAlarms;
else listModifier.mergeList(e.CurrentAlarms, AlarmList1);
/*Start the analysis process in a seperate task and return the Alarm_Group-List*/
return Analyser1.startAnalysis(PlantModelReader1, AlarmlogReader1, RuleBaseLoader1, AlarmList1);
});
Cursor = Cursors.Wait;
List<Analyser.ALARM_GROUP> alarmGroupList = analysertask.Result;
showAlarmLog(alarmGroupList);
Cursor = Cursors.Arrow;
Unfortunately the UI still is stuck when I start analyzing process and I don't even know if my concept of starting a new thread every two seconds(average appearance time of new alarms) is a reasonable concept.
I guess the problem is inside showAlarmLog but it is a lot of code. If needed I will post this code, too.
I would be thankful for any suggestions on this problem, even a "your concept is crap, try this idea: ..." would be good to know.
Kind regards
Larimow
The problem is that this call:
List<Analyser.ALARM_GROUP> alarmGroupList = analysertask.Result;
Blocks the UI thread until the background task is completed.
The way to handle this is to use a continuation task instead of waiting on the result:
Task<List<Analyser.ALARM_GROUP>> analysertask = Task.Factory.StartNew<List<Analyser.ALARM_GROUP>>(
()=> {
// Keep existing code
return Analyser1.startAnalysis(PlantModelReader1, AlarmlogReader1, RuleBaseLoader1, AlarmList1);
});
// Make a continuation here...
analysertask.ContinueWith( t =>
{
Cursor = Cursors.Wait;
List<Analyser.ALARM_GROUP> alarmGroupList = t.Result;
showAlarmLog(alarmGroupList);
Cursor = Cursors.Arrow;
}, TaskScheduler.FromCurrentSynchronizationContext());
By scheduling this as a continuation, it will run when the first task completes. By using TaskScheduler.FromCurrentSynchronizationContext, you say to marshal this back onto the UI thread when it executes.
Note that this becomes far easier with .NET 4.5/C# 5. With C# 5, you could write this as:
var analysertask = Task.Run(
()=> {
// Keep existing code
return Analyser1.startAnalysis(PlantModelReader1, AlarmlogReader1, RuleBaseLoader1, AlarmList1);
});
Cursor = Cursors.Wait;
List<Analyser.ALARM_GROUP> alarmGroupList = await analysertask;
showAlarmLog(alarmGroupList);
Cursor = Cursors.Arrow;
This requires the method to be, itself, flagged with the new async keyword, however.
I've got my main form Form1 running the main bulk of my program.
I have a separate thread started to perform an algorithm.
When I run the method from the new thread, method MyAlgorithm() I get the error
InvalidOperationException with the message, "Control control name accessed from a thread other than the thread it was created on."
How do I get back to the original thread so that I can run the method to update my text boxes with the latest values?
This is the method that I want to run contained in Form1, the main class in my application.
// Reset the results values
public void ShowResults()
{
while (true)
{
loopsNum.Text = Convert.ToString(resultLoopsNum);
nodesVisitedNum.Text = Convert.ToString(resultNodesVisitedNum);
nodesResolvedNum.Text = Convert.ToString(resultNodesResolvedNum);
cpuLoopsNum.Text = Convert.ToString(resultCpuLoopsNum);
shortestPathCostNum.Text = Convert.ToString(resultShortestPathCost);
}
}
I've looked at the Invoke() methods, but I don't know how to get the original instance of my Form1 from the threaded method.
I'm invoking my thread like this...
// Set the algorithm method up in it's own thread
Thread thread = new Thread(new ThreadStart(MyAlgorithm));
// Run the algorithm
thread.Start();
How do I get back to the original thread so that I can run the method to update my text boxes with the latest values?
In Windows Forms, you'd either use Control.Invoke/BeginInvoke or use a BackgroundWorker and perform the update in the progress event handler.
In WPF you'd use Dispatcher.Invoke/BeginInvoke.
In C# 5 and .NET 4.5 you'll be able to use async methods which should make a lot of this much simpler...
I've looked at the Invoke() methods, but I don't know how to get the original instance of my Form1 from the threaded method.
If the "threaded method" is just an instance method of the Form, then you've already got the this reference. If it's not, you'll need to provide that information - ideally as an ISynchronizeInvoke to avoid a direct dependency on Windows Forms if you can express the "update" part separately. (That interface is somewhat deprecated these days, in favour of synchronization contexts, but it still works perfectly well.)
Have a look at Control.Invoke():
public void ShowResults()
{
while (true)
{
Thread.Sleep(1000); // don't spam the UI thread
if (this.InvokeRequired)
{
this.Invoke((Action)UpdateGui);
}
else
{
UpdateGui();
}
}
}
private void UpdateGui()
{
loopsNum.Text = Convert.ToString(resultLoopsNum);
nodesVisitedNum.Text = Convert.ToString(resultNodesVisitedNum);
nodesResolvedNum.Text = Convert.ToString(resultNodesResolvedNum);
cpuLoopsNum.Text = Convert.ToString(resultCpuLoopsNum);
shortestPathCostNum.Text = Convert.ToString(resultShortestPathCost);
}
You can use:
myform.Invoke(ShowResults);
There's other options here too:
Alternately use a System.Forms.Timer to call ShowResults periodically. Or another option would be not to use another thread to do the operation; do it in the GUI thread and call Application.DoEvents() from within the operation when you want to let the GUI update.
The first option is nice because it keeps you from accidentally flooding the GUI with Invoke requests, and the second option is nice because it's all on the GUI thread and allows you to have fine-grain control over when things get displayed on the GUI.
I am writing a GUI app for monitoring and I'd like to get some advice on it's logic. Basically all the app needs to do is connect to a distant server every x minutes, check if something was changed, get changes if any, act upon them (update local db and so on, depending on changes).
My first idea was:
Have a checkbox (monitoring on/off). On click (if checked) starts a Timer.
Timer launches a BackgroundWorker in it's Tick method.
DoWork method does the connecting / retrieving info stuff
a) on WorkDone handler method gets the info from background worker and does local updates with it
b) on WorkDone handler method triggers one or more of custom events "SomethingChanged" depending on changes it got; EventListeners handle local updates from there.
My main problem is calling Worker from Timer since I added Worker to the Form and now they are on different threads (is that correct description?) and then passing results around is a similar problem. I was reading about delegates but still not sure what to use when and how, and if it's really necessary in the first place. Do I need both bgWorker and Timer? Do I need custom events or can I just do all work inside workDone with Switch(result)? Is this general principle good in the first place, maybe there's something better and I am reinventing the wheel? Thank you in advance!
From an architecture point of view:
Message Queues decouple bits of your application. You can in Windows Forms applications rely on the Message Queue that Windows creates and manages for you. Google for PostMessage/GetMessage etc. This is generally called "message passing".
Typical Arcitecture
One part of your app "pushes" a request into a queue
Some other part of your app "pulls" a request from a queue and writes a result to a second queue.
The first part can then "pull" requests from the second "results" queue and display to a user.
So it looks like this:
App --> REQUESTS QUEUE --> processing engine --> RESULTS QUEUE --> App
The processing engine could be in the same app, on the same thread or in a different thread/process (or even different machine).
You can use simple queues : say a Queue<string>() (as long as you use locks to access it) or increase complexity or more and more complex/functional queues.
Issues with the naive strategy and other solutions ... things to think about:
What happens if you make a new request while the old one has not yet completed?
What happens if an error occurs? Do you want errors inline? You can use another queue for errors?
Do you want retries?
What happens if a message is lost? (i.e. a request was pushed, but no response comes in...)? There are transactional queues etc.
Sample Code
object oLock = new object();
Queue<string> requests = new Queue<string>();
Queue<string> responses = new Queue<string>();
Thread mThread;
AutoResetEvent mEvent = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
mThread = new Thread(ProcessingEngine);
mThread.IsBackground = true;
mThread.Start();
}
private void ProcessingEngine()
{
string result;
string request = null;
while (true)
{
try
{
mEvent.WaitOne();
lock (oLock)
{
request = requests.Dequeue();
}
var wc = new WebClient();
result = wc.DownloadString(request);
lock (oLock)
{
responses.Enqueue(result);
}
}
catch (Exception ex)
{
lock (oLock)
{
responses.Enqueue(ex.ToString());
}
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (oLock)
{
//Stick in a new request
requests.Enqueue("http://yahoo.com");
//Allow thread to start work
mEvent.Set();
//Check if a response has arrived
if (responses.Any())
{
var result = responses.Dequeue();
listBox1.Items.Add(result.Substring(1,200));
}
}
}
}
If you use System.Windows.Forms.Timer instead of System.Threading.Timer, your Tick handler will be called from Form's message loop and you'll have full access to all controls - it will be safe to call bgWorker.RunWorkerAsync(). As for retrieving results - RunWorkerCompleted is also called from message loop thread and you can safetly update your UI here.
The solution is simple - INVOKE back into the main thread. THere is an Invoke method on the winform control. This will basically change threads for execution to the UI thread, and allow you to manipulate the UI.
Do that "block" (i.e. not once per control but once when you have news).
[This appears to be a loooong question but I have tried to make it as clear as possible. Please have patience and help me...]
I have written a test class which supports an Async operation. That operation does nothing but reports 4 numbers:
class AsyncDemoUsingAsyncOperations
{
AsyncOperation asyncOp;
bool isBusy;
void NotifyStarted () {
isBusy = true;
Started (this, new EventArgs ());
}
void NotifyStopped () {
isBusy = false;
Stopped (this, new EventArgs ());
}
public void Start () {
if (isBusy)
throw new InvalidOperationException ("Already working you moron...");
asyncOp = AsyncOperationManager.CreateOperation (null);
ThreadPool.QueueUserWorkItem (new WaitCallback (StartOperation));
}
public event EventHandler Started = delegate { };
public event EventHandler Stopped = delegate { };
public event EventHandler<NewNumberEventArgs> NewNumber = delegate { };
private void StartOperation (object state) {
asyncOp.Post (args => NotifyStarted (), null);
for (int i = 1; i < 5; i++)
asyncOp.Post (args => NewNumber (this, args as NewNumberEventArgs), new NewNumberEventArgs (i));
asyncOp.Post (args => NotifyStopped (), null);
}
}
class NewNumberEventArgs: EventArgs
{
public int Num { get; private set; }
public NewNumberEventArgs (int num) {
Num = num;
}
}
Then I wrote 2 test programs; one as console app and another as windows form app. Windows form app works as expected when I call Start repeatedly:
But console app has hard time ensuring the order:
Since I am working on class library, I have to ensure that my library works correctly in all app models (Haven't tested in ASP.NET app yet). So I have following questions:
I have tested enough times and it appears to be working but is it OK to assume above code will always work in windows form app?
Whats the reason it (order) doesn't work correctly in console app? How can I fix it?
Not much experienced with ASP.NET. Will the order work in ASP.NET app?
[EDIT: Test stubs can be seen here if that helps.]
Unless I am missing something then given the code above I believe there is no way of guaranteeing the order of execution. I have never used the AsyncOperation and AsyncOperationManager class but I looked in reflector and as could be assumed AsyncOperation.Post uses the thread pool to execute the given code asynchronously.
This means that in the example you have provided 4 tasks will be queued to the thread pool synchronously in very quick succession. The thread pool will then dequeue the tasks in FIFO order (first in first out) but it's entirely possible for one of later threads to be scheduled before an earlier one or one of the later threads to complete before an earlier thread has completed its work.
Therefore given what you have there is no way to control the order in the way you desire. There are ways to do this, a good place to look is this article on MSDN.
http://msdn.microsoft.com/en-us/magazine/dd419664.aspx
I use a Queue you can then Enqueue stuff and Dequeue stuff in the correct order. This solved this problem for me.
The documentation for AsyncOperation.Post states:
Console applications do not synchronize the execution of Post calls. This can cause ProgressChanged events to be raised out of order. If you wish to have serialized execution of Post calls, implement and install a System.Threading.SynchronizationContext class.
I think this is the exact behavior you’re seeing. Basically, if the code that wants to subscribe to notifications from your asynchronous event wants to receive the updates in order, it must ensure that there is a synchronization context installed and that your AsyncOperationManager.CreateOperation() call is run inside of that context. If the code consuming the asynchronous events doesn’t care about receiving them in the correct order, it simply needs to avoid installing a synchronization context which will result in the “default” context being used (which just queues calls directly to the threadpool which may execute them in any order it wants to).
In the GUI version of your application, if you call your API from a UI thread, you will automatically have a synchronization context. This context is wired up to use the UI’s message queueing system which guarantees that posted messages are processed in order and serially (i.e., not concurrently).
In a Console application, unless if you manually install your own synchronization context, you will be using the default, non-synchronizing threadpool version. I am not exactly sure, but I don’t think that .net makes installing a serializing synchronization context very easy to do. I just use Nito.AsyncEx.AsyncContext from the Nito.AsyncEx nuget package to do that for me. Basically, if you call Nito.AsyncEx.AsyncContext.Run(MyMethod), it will capture the current thread and run an event loop with MyMethod as the first “handler” in that event loop. If MyMethod calls something that creates an AsyncOperation, that operation increments an “ongoing operations” counter and that loop will continue until the operation is completed via AsyncOperation.PostOperationCompleted or AsyncOperation.OperationCompleted. Just like the synchronization context provided by a UI thread, AsyncContext will queue posts from AsyncOperation.Post() in the order it receives them and run them serially in its event loop.
Here is an example of how to use AsyncContext with your demo asynchronous operation:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting SynchronizationContext");
Nito.AsyncEx.AsyncContext.Run(Run);
Console.WriteLine("SynchronizationContext finished");
}
// This method is run like it is a UI callback. I.e., it has a
// single-threaded event-loop-based synchronization context which
// processes asynchronous callbacks.
static Task Run()
{
var remainingTasks = new Queue<Action>();
Action startNextTask = () =>
{
if (remainingTasks.Any())
remainingTasks.Dequeue()();
};
foreach (var i in Enumerable.Range(0, 4))
{
remainingTasks.Enqueue(
() =>
{
var demoOperation = new AsyncDemoUsingAsyncOperations();
demoOperation.Started += (sender, e) => Console.WriteLine("Started");
demoOperation.NewNumber += (sender, e) => Console.WriteLine($"Received number {e.Num}");
demoOperation.Stopped += (sender, e) =>
{
// The AsyncDemoUsingAsyncOperation has a bug where it fails to call
// AsyncOperation.OperationCompleted(). Do that for it. If we don’t,
// the AsyncContext will never exit because there are outstanding unfinished
// asynchronous operations.
((AsyncOperation)typeof(AsyncDemoUsingAsyncOperations).GetField("asyncOp", BindingFlags.NonPublic|BindingFlags.Instance).GetValue(demoOperation)).OperationCompleted();
Console.WriteLine("Stopped");
// Start the next task.
startNextTask();
};
demoOperation.Start();
});
}
// Start the first one.
startNextTask();
// AsyncContext requires us to return a Task because that is its
// normal use case.
return Nito.AsyncEx.TaskConstants.Completed;
}
}
With output:
Starting SynchronizationContext
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
SynchronizationContext finished
Note that in my example code I work around a bug in AsyncDemoUsingAsyncOperations which you should probably fix: when your operation stops, you never call AsyncOperation.OperationCompleted or AsyncOperation.PostOperationCompleted. This causes AsyncContext.Run() to hang forever because it is waiting for the outstanding operations to complete. You should make sure that your asynchronous operations complete—even in error cases. Otherwise you might run into similar issues elsewhere.
Also, my demo code, to imitate the output you showed in the winforms and console example, waits for each operation to finish before starting the next one. That kind of defeats the point of asynchronous coding. You can probably tell that my code could be greatly simplified by starting all four tasks at once. Each individual task would receive its callbacks in the correct order, but they would all make progress concurrently.
Recommendation
Because of how AsyncOperation seems to work and how it is intended to be used, it is the responsibility of the caller of an asynchronous API that uses this pattern to decide if it wants to receive events in order or not. If you are going to use AsyncOperation, you should document that the asynchronous events will only be received in order by the caller if the caller has a synchronization context that enforces serialization and suggest that the caller call your API on either a UI thread or in something like AsyncContext.Run(). If you try to use synchronization primitives and whatnot inside of the delegate you call with AsyncOperation.Post(), you could end up putting threadpool threads in a sleeping state which is a bad thing when considering performance and is completely redundant/wasteful when the caller of your API has properly set up a synchronization context already. This also enables the caller to decide that, if it is fine with receiving things out of order, that it is willing to process events concurrently and out of order. That may even enable speedup depending on what you’re doing. Or you might even decide to put something like a sequence number in your NewNumberEventArgs in case the caller wants both concurrency and still needs to be able to assemble the events into order at some point.