Acceptable use of Thread.Sleep() - c#

I'm working on a console application which will be scheduled and run at set intervals, say every 30 minutes. Its only purpose is to query a Web Service to update a batch of database rows.
The Web Service API reccommends calling once every 30 seconds, and timeout after a set interval. The following pseudocode is given as an example:
listId := updateList(<list of terms>)
LOOP
WHILE NOT isUpdatingComplete(listId)
END LOOP
statuses := getStatuses(“LIST_ID = {listId}”)
I have coded this roughly in C# as:
int callCount = 0;
while( callCount < 5 && !client.isUpdateComplete(listId, out messages) )
{
listId = client.updateList(options, terms, out messages);
callCount++;
Thread.Sleep(30000);
}
// Get resulting status...
Is it OK in this situation to use Thread.Sleep()? I'm aware it is not generally good practice but from reading reasons not to use it this seems like acceptable usage.
Thanks.

Thread.Sleep ensures the current thread doesn't return until at least the specified milliseconds have passed. There are plenty of places it's appropriate to do that, and your example seems fine, assuming it's running on a background thread.
Some example places you don't want to use it - on the UI thread or where you need to do exact timing.

Generally speaking, Thread.Sleep is like any other tool: perfectly OK to use, except when it's terribly misused. I disagree with the "not generally good practice" part, which is the result of people abusing Thread.Sleep when they should be doing something else (i.e. blocking on a synchronization object).
In your case the program is single-threaded, it has no UI (i.e. the thread has no message loop) and you do not want to synchronize with external events. Therefore Thread.Sleep is just fine.

The general objection against Sleep() is that it wastes a Thread.
In your case there is only 1 Thread (maybe 2) so that is not really a problem.
So I think it looks fine (but I would sleep 29 seconds to cut some slack).

It's fine, except that you cannot interrupt it once it goes into sleep, without aborting the thread (which is not recommended).
That's why a ManualResetEvent might be a better idea, since it can be signalled ("awaken") from a different thread.

you could stick with the Thread.Sleep method. But it would be more elegant to schedule it to run every 30 minutes - so you don't have to take care of the waiting inside your application.

Thread.Sleep isn't the best for executing periodic logic. Thread.Sleep(n) means your thread will relinquish control for n milliseconds. There is no guarantee that it will regain control after n milliseconds, it depends on the CPU load.

If you are locking the thread for 30 mins case you should schedule a windows task every 30 mins, so the program executes and then ends. That way you are not locking a thread for so long.
For shorter times, like 30 secs / 1 min, System.Thread.Sleep() is perfectly fine. For more than 5 mins i would use a windows task. (Im spanish i think on the english version are called like that, im talking about the tasks you schedule from the control panel ;-) )

Related

Sleeping/waiting for a long time

I am designing an industrial hardware control program in C#, which will run for periods of 72 hours at a time talking over serial ports.
In psuedo-code, what I am trying to do looks like this:-
while(true) {
TalkToSerialPort1();
WaitForXHours(3);
TalkToSerialPort2();
WaitForXHours(1);
// etc
}
I have this code in a separate thread from my main console or GUI program and has to be run procedureally
It seems like Thread.Sleep() for long periods of time seems to be ruining my day! I am looking for a reliable way of sleeping for extended periods of time.
Any information would be helpful.
You should use Quartz .NET it is reliable and very accurate scheduler.
Read more here: https://www.quartz-scheduler.net/
Alternative approach would be to use a Timer
for example calling method on every x minutes
Note : that in this case - You must ensure that previous operation has finished, before starting a new one.
A Stopwatch is a better way to solve this**. For example:
Stopwatch spw = new Stopwatch();
int stepNo = 0;
while (!haltWork)
{
Thread.Sleep(100);
switch (stepNo)
{
case 0:
TalkToSerialPort1();
spw.Restart();
stepNo += 1;
break;
case 1:
if (spw.Elapsed.Hours >= 3)
{
TalkToSerialPort2();
spw.Restart();
stepNo += 1;
}
break;
case 2:
if (spw.Elapsed.Hours >= 1)
{
TalkToSerialPort3();
spw.Restart();
stepNo += 1;
}
break;
// etc...
}
}
Here I've added a condition haltWork - your main program will need some way to signal this thread to exit in a timely fashion if necessary. This runs the thread in a polling loop that will allow it to break and exit, supports user cancellation, and, because of the stopwatch, will provide you the precise time elapsed for the current step in the case of user cancellation that you can use for process diagnostics, restart procedures, etc.
The procedural process is broken up into steps using a switch statement. This lets you perform long running procedural processes with waiting or polling steps in a clean and logical manner while also remaining responsive, able to provide active feedback (consider raising events periodically to alert the main thread of your current step, time elapsed, etc, for process logging purposes).
Note also that this example resets the stopwatch at each step - how you do this depends on your requirements; whether you need to control the interval between steps or whether it is more important to keep regular pace with respect to an arbitrary reference. If the latter, naturally just start the stopwatch once and make the rest of your intervals absolute rather than relative.
** I am proceeding from the assumption that doing this inside your C# application has been thought out carefully and that this is the best place to take responsibility for this task.
The windows task scheduler is one alternative place to handle repetitive "headless" tasks that need to be run at long intervals.
Another alternative, especially relevant to industrial control, is to use dedicated hardware to do this - a small PLC, etc.
well - if You want to stick to the "while (true)" pattern,
what You can do is smth like this:
while (true){
if (DateTime.Now - LastExecutionDate > 72h)
{
doYourStuff();
Update_LastExecutionDate;
}
else{
continue; //or sleep for 5 minutes
}

Ten times Thread.Sleep(100) or a single Thread.Sleep(1000)?

Is there a difference (from performance perspective) between:
Thread.Sleep(10000);
and
for(int i=0; i<100; i++)
{
Thread.Sleep(100);
}
Does the single call to Thread.Sleep(10000) also results in context switches within this 10 seconds (so the OS can see if it's done sleeping), or is this thread really not served for 10 seconds?
The second code (for loop) requires more process swaps and should be little slower than Thread.Sleep(10000);
Anyway you can use System.Diagnostics.Stopwatch class to determine the exact time for these two approaches. I believe the difference will be very very small.
in any case second loop will take time because of following overheads
Memory utilization for 10 different thread objects
10 different callbacks will be initiated once you call thread.sleep
Overhead cost for running loop
if we want to run the code on single thread so why do we want a loop if we don't have any break point even.

Which way is better, and how to pass parameters to windows.forms.timer

What I want to accomplish it the following thing:
I have a lot of "checks(if/else if etc)" inside a timer, that his interval is 1000 ms,
there is a text file that getting updated and the timer read it every 1000 ms and check for some specific changes,
under 1 of those conditions if it is true the timer, i need to wait 10 sec and then read another text file and then continue with the rest of the timer code.
but in the mean time the timer keep running under those 10 sec and preform the checks every 1sec for all the other conditions and this 1 also.
what i thought to do it
if the conditions i wanted it true i will start a new timer with 10sec interval and it will continue with the code of that specific part.
but what i have hard time to accomplish is how to pass parameters into that timer
such as
newTimer.Start(int "parameter", string "parameter b", list<string> parameters c")
etc etc
or if you got any other idea i will be glad to hear.
To pass parameters, you can always use Tuple.
newTimer.Start(Tuple.Create(param1, param2, param3));
You might not need to have two timer if you do the logic correctly.
Timer *run every second*
Check file
If file has flag Then save in variable the current date + 10 seconds
If current date > saved date Then Check the other file
You need to consider that a System.Windows.Forms.Timer will run on the GUI thread (the thread that run the containing form's message loop / pump), as it uses window messages (WM_TIMER) that are processed by the GUI thread. Because of that, any code that runs under any System.Windows.Forms.Timer in your form will execute synchronously. So, if your start a new System.Windows.Forms.Timer which blocks for 10 seconds, all your other timers will be blocked as well (since the message loop is blocked).
Consider using a System.Threading.Timer or System.Timers.Timer, as they run the timer callback on a different thread. This way, your code will run pretty much as you'd want - every one second the method will be running, regardless of weather the previous call completed or is still blocking (waiting 10 seconds).

How to introduce a delay between webrequests to a site in C#?

I am making multiple requests to a website. How can I introduce a delay between requests to slow down my process? Is there a method that allows me to just cause the thread to wait for X seconds before proceeding?
Are you looking for Thread.Sleep?
Note that it causes the current thread to sleep - you don't target it at a different thread. But if you've got a loop within one thread, making multiple requests, you could easily add it in to the loop to restrict your request rate.
The Sleep method is overloaded - one signature takes a TimeSpan and the other takes a number of milliseconds. Personally I'd generally prefer the first one, as it leaves no room for ambiguity. For example:
Thread.Sleep(TimeSpan.FromSeconds(2));
is obviously asking the thread to sleep for 2 seconds - not 2 minutes, 2 milliseconds etc.
System.Threading.Thread.Sleep(x);
…where x is the number of milliseconds to sleep the thread.
An alternative is to use a Timer and do a request each time the Tick event fires.

multithread performance problem for web service call

Here is my sample program for web service server side and client side. I met with a strnage performance problem, which is, even if I increase the number of threads to call web services, the performance is not improved. At the same time, the CPU/memory/network consumption from performance panel of task manager is low. I am wondering what is the bottleneck and how to improve it?
(My test experience, double the number of threads will almost double the total response time)
Client side:
class Program
{
static Service1[] clients = null;
static Thread[] threads = null;
static void ThreadJob (object index)
{
// query 1000 times
for (int i = 0; i < 100; i++)
{
clients[(int)index].HelloWorld();
}
}
static void Main(string[] args)
{
Console.WriteLine("Specify number of threads: ");
int number = Int32.Parse(Console.ReadLine());
clients = new Service1[number];
threads = new Thread[number];
for (int i = 0; i < number; i++)
{
clients [i] = new Service1();
ParameterizedThreadStart starter = new ParameterizedThreadStart(ThreadJob);
threads[i] = new Thread(starter);
}
DateTime begin = DateTime.Now;
for (int i = 0; i < number; i++)
{
threads[i].Start(i);
}
for (int i = 0; i < number; i++)
{
threads[i].Join();
}
Console.WriteLine("Total elapsed time (s): " + (DateTime.Now - begin).TotalSeconds);
return;
}
}
Server side:
[WebMethod]
public double HelloWorld()
{
return new Random().NextDouble();
}
thanks in advance,
George
Although you are creating a multithreaded client, bear in mind that .NET has a configurable bottleneck of 2 simultaneous calls to a single host. This is by design.
Note that this is on the client, not the server.
Try adjusting your app.config file in the client:
<system.net>
<connectionManagement>
<add address=“*” maxconnection=“20″ />
</connectionManagement></system.net>
There is some more info on this in this short article :
My experience is generally that locking is the problem: I had a massively parallel server once that spent more time context switching than it did performing work.
So - check your memory and process counters in perfmon, if you look at context switches and its high (more than 4000 per second) then you're in trouble.
You can also check your memory stats on the server too - if its spending all its time swapping, or just creating and freeing strings, it'll appear to stall also.
Lastly, check disk I/O, same reason as above.
The resolution is to remove your locks, or hold them for a minimum of time. Our problem was solved by removing the dependence on COM BSTRs and their global lock, you'll find that C# has plenty of similar synchronisation bottlenecks (intended to keep your code working safely). I've seen performance drop when I moved a simple C# app from a single-core to a multi-core box.
If you cannot remove the locks, the best option is not to create as many threads :) Use a thread pool instead to let the CPU finish one job before starting another.
I don't believe that you are running into a bottleneck at all actually.
Did you try what I suggested ?
Your idea is to add more threads to improve performance, because you are expecting that all of your threads will run perfectly in parallel. This is why you are assuming that doubling the number of threads should not double the total test time.
Your service takes a fraction of a second to return and your threads will not all start working at exactly the same instant in time on the client.
So your threads are not actually working completely in parallel as you have assumed, and the results you are seeing are to be expected.
You are not seeing any performance gain because there is none to be had. The one line of code in your service (below) probably executes without a context switch most of the time anyway.
return new Random().NextDouble();
The overhead involved in the web service call is higher than than the work you are doing inside of it. If you have some substantial work to do inside the service (database calls, look-ups, file access etc) you may begin to see some performance increase.
Just parallelizing a task will not automatically make it faster.
-Jason
Of course adding Sleep will not improve performance.
But the point of the test is to test with a variable number of threads.
So, keep the Sleep in your WebMethod.
And try now with 5, 10, 20 threads.
If there are no other problems with your code, then the increase in time should not be linear as before.
You realize that in your test, when you double the amount of threads, you are doubling the amount of work that is being done. So if your threads are not truly executing in parallel, then you will, of course, see a linear increase in total time...
I ran a simple test using your client code (with a sleep on the service).
For 5 threads, I saw a total time of about 53 seconds.
And for 10 threads, 62 seconds.
So, for 2x the number of calls to the webservice, it only took 17% more time.. That is what you are expecting, no ?
Well, in this case, you're not really balancing your work between the chosen n.º of threads... Each Thread you create will be performing the same Job. So if you create n threads and you have a limited parallel processing capacity, the performance naturally decreases. Another think I notice is that the required Job is a relatively fast operation for 100 iterations and even if you plan on dividing this Job through multiple threads you need to consider that the time spent in context switching, thread creation/deletion will be an important factor in the overall time.
As bruno mentioned, your webmethod is a very quick operation. As an experiment, try ensuring that your HelloWorld method takes a bit longer. Throw in a Thread.Sleep(1000) before you return the random double. This will make it more likely that your service is actually forced to process requests in parallel.
Then try your client with different amounts of threads, and see how the performance differs.
Try to use some processor consuming task instead of Thread.Sleep. Actually combined approach is the best.
Sleep will just pass thread's time frame to another thread.
IIS AppPool "Maximum Worker Processes" is set to 1 by default. For some reason, each worker process is limited to process 10 service calls at a time. My WCF async server-side function does Sleep(10*1000); only.
This is what happens when Maximum Worker Processes = 1
http://s4.postimg.org/4qc26cc65/image.png
alternatively
http://i.imgur.com/C5FPbpQ.png?1
(First post on SO, I need to combine all pictures into one picture.)
The client is making 48 async WCF WS calls in this test (using 16 processes). Ideally this should take ~10 seconds to complete (Sleep(10000)), but it takes 52 seconds. You can see 5 horizontal lines in the perfmon picture (above link) (using perfmon for monitoring Web Service Current Connections in server). Each horizontal line lasts 10 seconds (which Sleep(10000) does). There are 5 horizontal lines because the server processes 10 calls each time then closes that 10 connections (this happens 5 times to process 48 calls). Completion of all calls took 52 seconds.
After setting Maximum Worker Processes = 2
(in the same picture given above)
This time there are 3 horizontal lines because the server processes 20 calls each time then closes that 20 connections (this happens 3 times to process 48 calls). Took 33 secs.
After setting Maximum Worker Processes = 3
(in the same picture given above)
This time there are 2 horizontal lines because the server processes 30 calls each time. (happens 2 times to process 48 calls) Took 24 seconds.
After setting Maximum Worker Processes = 8
(in the same picture given above)
This time there is 1 horizontal line because the server processes 80 calls each time. (happens once to process 48 calls) Took 14 seconds.
If you don't care this situation, your parallel (async or threaded) client calls will be queued by 10s in the server, then all of your threaded calls (>10) won't get processed by the server in parallel.
PS: I was using Windows 8 x64 with IIS 8.5. The 10 concurrent request limit is for workstation Windows OSes. Server OSes doesn't have that limit according to another post on SO (I can't give link due to rep < 10).

Categories