I am trying to make my foreach loop asynchronous. The loop loops the first time, does something then it will wait 40 seconds and then the loop loops again does something, waits 40 seconds etc...
In my situation I am looping around tweets, getting the tweet user name and then sending a tweet to them.
I tried using the Thread.Sleep(40000) method but that just freezes the app and I can't use it, and the loop doesn't stop for 40 seconds and then loops again. The app freezes but the loop doesn't, the tweets are getting sent without even waiting at all. This how my code looks like
private void tweetButton_Click(object sender, EventArgs e)
{
var tweets= .........
foreach (var tweet in tweets)
{
// Do Something
System.Threading.Thread.Sleep(40000);
}
How would I let the foreach loop to pause before looping again on its self, and how would I make it pause without freezing my application?
https://msdn.microsoft.com/en-us/library/hh194873(v=vs.110).aspx
I think you can await Task.Delay(40000); - to me that would be an 'async sleep' like you've asked for.
Alternatively, you could kick off a timer. The timer is probably a better choice, but will run on a threadpool thread.
EDIT: Not sure why this got -1...but if anyone has an explanation, I'd be interested.
I've verified that 'await Task.Delay(xyz)' does work for this purpose. Naturally, you'd need the async keyword to be added.
static async void DoSomething()
{
for(var i = 0;i<25;i++)
{
// Do Something
await Task.Delay(1000);
Console.WriteLine("Sending a Tweet");
}
}
I can't speak to the performance, but it seems to work fine for me.
You want your code to run on a different thread, so it doens note impede the code running in your winforms gui thread.
The best way for you specific needs is a timer that you kickoff once and that then does your job.
{
Timer t = new Timer();
t.Interval = 50000;
t.Elapsed += T_Elapsed;
t.Start();
}
private static void T_Elapsed(object sender, ElapsedEventArgs e)
{
}
If you need to access your winforms controls from here, you can use invoke, so the commands are placed into the the gui threads message loop.
control.Invoke((MethodInvoker)(() =>
{
//Do your thing
}));
You could implement background process in form. That would works in your case.
Related
I'm trying to use background worker to update a text label continuously, but for DoWork, if no loop used, it will only execute once, but if infinite loop is used, it freezes the GUI, any idea to solve this? Really appreciate!!! I'm pretty new to C# and still trying to learn.
Here's my code:
This in the main form:
backgroundWorkerX.DoWork += backgroundWorkerX_DoWork;
backgroundWorkerX.ProgressChanged += backgroundWorkerX_ProgressChanged;
backgroundWorkerX.WorkerReportsProgress = true;
backgroundWorkerX.RunWorkerAsync();
Then:
public void backgroundWorkerX_DoWork(object sender, DoWorkEventArgs e)
{
X = -(RSSI_PI1_ST1);
backgroundWorkerX.ReportProgress(X);
}
public void backgroundWorkerX_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label9.Text = e.ProgressPercentage.ToString();
}
public void backgroundWorkerX_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
[...] if no loop used, it will only execute once
This is the expected behavior. It will do the thing it's expected and then call RunWorkerCompleted.
[...] but if infinite loop is used, it freezes the GUI.
You don't present a loop in your question. So I'll make an assumption and will give you an educated guess that it actually consumes all the CPU, and therefore crashes the GUI.
// I assume that you loop like this somehow.
do
{
X = -(RSSI_PI1_ST1);
backgroundWorkerX.ReportProgress(X);
} while (true);
Try to add something to "slow it down" once in a while. Otherwise it will just run and run as fast as possible, and therefore consume all the CPU available. Remember that everytime you use ReportProgress it will be rendered by the GUI-thread. And this will execute very often and not leave a lot of resources for the GUI thread to respond to other things. Below I use Thread.Sleep, which will pause the thread for half a second. But remember that you will only want to do this in a background thread.
do
{
X = -(RSSI_PI1_ST1);
backgroundWorkerX.ReportProgress(X);
Thread.Sleep(500);
} while (true);
I would also consider doing this another way. If you actually have the need of pausing the thread, you might as well do it with a Timer. Thread.Sleep will lock the thread, and may therefore not be what you really want. From this answer:
Process() // method to be called after regular interval in Timer
{
// lengthy process, i.e. data fetching and processing etc.
// here comes the UI update part
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
}
Hi I am trying to find a method of waiting a number of milliseconds before moving to the next line of code,
I have looked into Thread.Sleep but this will freeze the main form, I would like this to remain active.
I tried timers and stopwatches and both freeze the main form when they should be posting to a console when they tick.
I couldn't find a way of using task.delay or background worker in the wait I wanted either.
Pseudo Code:
Wait 2 - 6 seconds
Log "waiting"
Log "waiting"
Log "waiting"
Stop Waiting - Run next line of code.
The methods I have tried just freeze up the form and fill the log afterwards, I just want a simple method of waiting without freezing the form and without having to deal with events being called which would mean the next line isn't run.
Any help would be awesome because I am still new to c# and its been driving me a bit mad :(
The await keyword, in conjunction with Task.Delay makes this trivial.
public async Task Foo()
{
await Task.Delay(2000);
txtConsole.AppendText("Waiting...");
DoStuff();
}
Try using a DispatcherTimer. It's a pretty handy object that does all the work of delegating to the UI thread.
For example:
private DispatcherTimer _dtTimer = null;
public Constructor1(){
_dtTimer = new DispatcherTimer();
_dtTimer.Tick += new System.EventHandler(HandleTick);
_dtTimer.Interval = new TimeSpan(0, 0, 0, 2); //Timespan of 2 seconds
_dtTimer.Start();
}
private void HandleTick(object sender, System.EventArgs e) {
_uiTextBlock.Text = "Timer ticked!";
}
Timer should work fine in this case, unless you put Thread.Sleep in its handler or the handler itself takes too much time to complete.
You haven't specified the UI framework that you use or .Net version, but for the latest .Net you can use async/await. That way, UI would not be frozen while your code awaits for the background task
void async MyMethod()
{
var result = await Task.Run(() => long_running_code);
}
DateTime Tthen = DateTime.Now;
do
{
Application.DoEvents();
} while (Tthen.AddSeconds(5) > DateTime.Now);
See the code at the bottom of this post. It's supposed to add "3" to the listbox, then "2" a second later, then "1" a second later and then run the main code of the program. However, once I execute the program it just stays blank 3 seconds long, after which all 3, 2, and 1 are shown, after which all the code directly starts. I want to visually see every number show up with a one second delay. How do I do this?
private void Main()
{
countdown();
//Main Code
}
private void countdown()
{
listBox1.Items.Clear();
listBox1.Items.Add("3");
System.Threading.Thread.Sleep(1000);
listBox1.Items.Add("2");
System.Threading.Thread.Sleep(1000);
listBox1.Items.Add("1");
System.Threading.Thread.Sleep(1000);
listBox1.Items.Clear();
}
async / await to the rescue:
private async void OnButtonClick(object sender, EventArgs e)
{
listBox1.Items.Clear();
listBox1.Items.Add("3");
await Task.Delay(1000);
listBox1.Items.Add("2");
await Task.Delay(1000);
listBox1.Items.Add("1");
await Task.Delay(1000);
listBox1.Items.Clear();
}
First: Why isn't anything happening?
The reason is, that you are currently in the UI thread. By doing Thread.Sleep you suspend the very same thread you expect to draw the items you just added.
Second: How to work around this?
As #CodeCaster mentioned, you could use a Timer to do all this. You could also put your code in a Thread and call the Add method by using a Dispatcher or the SynchronizationContext class and it's Send method.
Third: A small hint on the Sleep method.
Usually it should do what you expect it to, but there is no guarantee for that. Calling Sleep means that your thread will be suspended for roughly the amount of time you want it to. See this answer
You can use a Timer having the interval set to 1000. Start the timer when you want it to raise Tick event. Stop it to stop raising Tick event. Handle the Tick event and run the code in intervals.
But to have a countdown 3-2-1 function using async-await as it's suggested in the other answer is good idea:
private async void countdown()
{
listBox1.Items.Clear();
listBox1.Items.Add("3");
await Task.Delay(1000);
listBox1.Items.Add("2");
await Task.Delay(1000);
listBox1.Items.Add("1");
await Task.Delay(1000);
listBox1.Items.Clear();
}
Put a listBox1.Refresh(); after every Sleep() call.
You are letting the thread sleep, but the UI does not get repainted automagically.
Suppose you have a search textbox and have a search algorithm attached to the TextChanged event, that runs with a BackgroundWorker. If there comes a new character in the textbox, i need to cancel the previous search and run it again.
I tried using events in between the main thread and the bgw, from this previous question, but I still get the error "currently busy and cannot run multiple tasks concurrently"
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
private void txtSearch_TextChanged(object sender, EventArgs e)
{
SearchWithBgw();
}
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
void bgw_Search_DoWork(object sender, DoWorkEventArgs e)
{
Search(txtSearch.Text, e);
}
private void Search(string aQuery, DoWorkEventArgs e)
{
int i = 1;
while (i < 3) // simulating search processing...
{
Thread.Sleep(1000);
i++;
if (bgw_Search.CancellationPending)
{
_resetEvent.Set(); // signal that worker is done
e.Cancel = true;
return;
}
}
}
EDIT To reflect answers. DonĀ“t reuse the BackgroundWorker, create a new one:
private void SearchWithBgw()
{
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
bgw_Search = new BackgroundWorker();
bgw_Search.WorkerSupportsCancellation = true;
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
bgw_Search.RunWorkerAsync();
}
When the _resetEvent.WaitOne() call completes, the worker thread isn't actually done. It is busy returning from DoWork() and waiting for an opportunity to run the RunWorkerCompleted event, if any. That takes time.
There is no reliable way to ensure the BGW is completed in a synchronous way. Blocking on IsBusy or waiting for the RunWorkerCompleted event to run is going to cause deadlock. If you really want to use only one bgw then you'll have to queue the requests. Or just don't sweat the small stuff and allocate another bgw. They cost very little.
Create a new background worker if the old one exists.
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
Also I know you put fake code in, but you want to make sure you set _resetEvent when the code completes normally too.
Do not reuse a Backgroundworker. It is a cheap resource, it is not a Thread.
make sure your Bgw code stops, yours looks OK. The Bgw will release the Thread to the pool.
but in the mean time, create a new Task/Bgw for a new job.
You may want to unsubscribe your Completed event from the old Bgw.
I think you should consider not cancelling the background worker.
If you cancel requests and the user types faster than your server returns queries, he will not see suggestions until he is finished typing.
In interactive scenarios like this, It could be better to show responses that run behind with what the user's typing. Your user will know he can stop typing if the word he has in mind is your suggestions list.
This will be also better for your server when it is busy, because instead of many cancelled requests, who will cost something but that are ultimately not shown, there will be fewer requests whose response you actually use.
I ran into similar issues with (3d) rendering applications, where the beginner's mistake is to cancel and rerender on every mousemove. This lead to a lot of computation and little interactive feedback.
I need to do a sort of "timeout" or pause in my method for 10 seconds (10000 milliseconds), but I'm not sure if the following would work as i do not have multi-threading.
Thread.Sleep(10000);
I will try to use that current code, but I would appreciate if someone could explain the best and correct way of doing this, especially if the above code does not work properly. Thanks!
UPDATE: This program is actually a console application that in the function in question is doing many HTTPWebRequests to one server, so I wish to delay them for a specified amount of milliseconds. Thus, no callback is required - all that is needed is an "unconditional pause" - basically just the whole thing stops for 10 seconds and then keeps going. I'm pleased that C# still considers this as a thread, so Thread.Sleep(...) would work. Thanks everybody!
You may not have multi-threading, but you're still executing within a thread: all code executes in a thread.
Calling Thread.Sleep will indeed pause the current thread. Do you really want it to unconditionally pause for 10 seconds, or do you want to be able to be "woken up" by something else happening? If you're only actually using one thread, calling Sleep may well be the best way forward, but it will depend on the situation.
In particular, if you're writing a GUI app you don't want to use Thread.Sleep from the UI thread, as otherwise your whole app will become unresponsive for 10 seconds.
If you could give more information about your application, that would help us to advise you better.
Thread.Sleep is fine, and AFAIK the proper way. Even if you are not Multithreaded: There is always at least one Thread, and if you send that to sleep, it sleeps.
Another (bad) way is a spinlock, something like:
// Do never ever use this
private void DoNothing(){ }
private void KillCPU()
{
DateTime target = DateTime.Now.AddSeconds(10);
while(DateTime.Now < target) DoNothing();
DoStuffAfterWaiting10Seconds();
}
This is sadly still being used by people and while it will halt your program for 10 seconds, it will run at 100% CPU Utilization (Well, on Multi-Core systems it's one core).
That will indeed pause the executing thread/method for 10 seconds. Are you seeing a specific problem?
Note that you shouldn't Sleep the UI thread - it would be better to do a callback instead.
Note also that there are other ways of blocking a thread that allow simpler access to get it going again (if you find it is OK after 2s); such as Monitor.Wait(obj, 10000) (allowing another thread to Pulse if needed to wake it up):
static void Main() {
object lockObj = new object();
lock (lockObj) {
new Thread(GetInput).Start(lockObj);
Monitor.Wait(lockObj, 10000);
}
Console.WriteLine("Main exiting");
}
static void GetInput(object state) {
Console.WriteLine("press return...");
string s = Console.ReadLine();
lock (state) {
Monitor.Pulse(state);
}
Console.WriteLine("GetInput exiting");
}
You can do this with Thread.Interrupt too, but IMO that is messier.
You could use a separate thread to do it:
ThreadPool.QueueUserWorkItem(
delegate(object state)
{
Thread.Sleep(1000);
Console.WriteLine("done");
});
But, if this is a Windows Forms app, you will need to invoke the code after the delay from the Gui thread (this article, for example: How to update the GUI from another thread in C#?).
[Edit] Just saw your update. If it's a console app, then this will work. But if you haven't used multiple threads so far, then you need to be aware that this code will be executed in a different thread, which means you will have to take care about thread synchronization issues.
If you don't need background workers, stick to "keeping it simple".
Here is a pause class that will pause for the desired milliseconds and wont consume your CPU resources.
public class PauseClass
{
//(C) Michael Roberg
//Please feel free to distribute this class but include my credentials.
System.Timers.Timer pauseTimer = null;
public void BreakPause()
{
if (pauseTimer != null)
{
pauseTimer.Stop();
pauseTimer.Enabled = false;
}
}
public bool Pause(int miliseconds)
{
ThreadPriority CurrentPriority = Thread.CurrentThread.Priority;
if (miliseconds > 0)
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
pauseTimer = new System.Timers.Timer();
pauseTimer.Elapsed += new ElapsedEventHandler(pauseTimer_Elapsed);
pauseTimer.Interval = miliseconds;
pauseTimer.Enabled = true;
while (pauseTimer.Enabled)
{
Thread.Sleep(10);
Application.DoEvents();
//pausThread.Sleep(1);
}
pauseTimer.Elapsed -= new ElapsedEventHandler(pauseTimer_Elapsed);
}
Thread.CurrentThread.Priority = CurrentPriority;
return true;
}
private void pauseTimer_Elapsed(object sender, ElapsedEventArgs e)
{
pauseTimer.Enabled = false;
}
}
Yes, that works just fine.
You don't have to have multiple threads to make use of some of the methods in the Thread class. You always have at least one thread.
For a timeout, you should have a static volatile boolean isRunning class field. When the new thread starts, the isRunning must become true, and at the end must become false.
The main thread should have a method that loops for the isRunning during the timeout you define. When the timeout ends, you should implement the logic. But, never use the abort thread method.
A pause... there isn't a straightforward solution. It depends on what you are doing inside the thread. However, you could look at Monitor.Wait.
If you can have an async method, you can do something like to pause the function at a certain location. Once pause is set false it will continue executing the rest of the code in the method. Since this is an async method and delay is async too UI execution wouldn't be affected.
* Please note that asyn is supported only in .net 4.5 and higher.
bool pause = true;
void async foo()
{
//some code
while (pause)
{
await Task.Delay(100);
}
//some code
}