locked
Thread.Sleep performance issue when multithreading. RRS feed

  • Question

  • I have a Wcf service which is getting 400 request per second. I haven't use Thread or Task for it. In middle of code I am executing external exe and update database. For this it is taking 5s. Therefore I used Thread.Sleep(5000) right after executing that external Exe. After 5 seconds I am getting database record and continue the program. 

    This is works fine around 10-20 requests per seconds. But increasing requests it is taking more than 5s. Then I found out Thread.Sleep not only wait exact 5s and it is not good with time purposes. 

    Then I used while loop and break it after 5 seconds and it cause higher usage of my processor and stuck. 

    Are there any proper ways to wait for 5 seconds in multithreaded environments without harming performance?

    (exe does not delay, server has 16 cores and 18gb ram) 

    Thanks.


    chapneox

    Monday, June 16, 2014 12:22 PM

Answers

  • This approach seems like a complex equivalent to Thread.Sleep(). ManualResetEvent.WaitOne() still blocks the thread, and its exactly this syncronous style of blocking the thread that is limiting thoughput.

    As long as you block the thread (one way or another), you're going to have the same problem.

    Tuesday, June 17, 2014 12:25 PM

All replies

  • Are there any proper ways to wait for 5 seconds in multithreaded environments without harming performance?

    You could consider using a timer that fires only once, 5 seconds after it is started, before it is stopped: http://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx

      
    private void Method()
      {
       System.Timers.Timer timer = new System.Timers.Timer();
       timer.Elapsed += (sender, args) => 
       { 
        /* do something after five seconds*/ 
        timer.Stop();
        timer.Dispose();
       };
       timer.Interval = 5000;
       timer.Start();
      }

    Using a timer, the application will remain responsive during the five second delay.


    Monday, June 16, 2014 12:40 PM
  • I was trying to apply this with my scenario. Service should return a string after execute.

    Private string Method()
    {	
        //Call exe.	
        //Thread.Sleep(5000) - where the issue is	
        //string id = GetId();	
        //return id;
    }

    I tried this way,,It will give results like this, 5+ time

    request 1 - 8s

    request 2 - 13s

    request 3 - 18s

    private string GetId()
    {
         ManualResetEvent waitEvent = new ManualResetEvent(false);
          string text = string.Empty;
          System.Timers.Timer timer = new System.Timers.Timer();
          timer.Elapsed += (sender, args) =>
          {
              text = GetData();
              timer.Stop();
              timer.Dispose();
              waitEvent.Set();
          };
          timer.Interval = 5000;
          timer.Start();
          waitEvent.WaitOne();
    
          return text;
        }
    }
    Can you point out me what is the wrong here or are there any other ways of doing this?


    chapneox

    Monday, June 16, 2014 6:26 PM
  • Hi,

    The problem you are having here is that Thread.Sleep suspends the current thread, in this case for 5 seconds. This thread can do nothing else for this period. If you get many requests per second coming in, then your thread pool will have to vastly grow in size to accommodate this. This is very, very inefficient.

    You should redesign you software to use Task or async/await. This way a much smaller number of threads will be needed, because none of them are just sat blocked.

    Also, running up processes is not a particularly cheap thing to do in Windows, and spawn a new process for this volume of operations per second smells bad to me. It just doesn't scale well. Could you move the update into the WCF service, or possible refactor to updater to be always running, and receive commands somehow (for example over MSMQ)?

    Regards,

    Nick

    Monday, June 16, 2014 8:45 PM
  • I guess the GetId method should call the GetData method immediately and then wait five seconds before returning, right? Then you should call the GetData method before you start the timer:

    private string GetId()
            {
                ManualResetEvent waitEvent = new ManualResetEvent(false);
                string text = string.Empty;
                System.Timers.Timer timer = new System.Timers.Timer();
                timer.Elapsed += (sender, args) =>
                {
                      timer.Stop();
                      timer.Dispose();
                      waitEvent.Set();
                };
                timer.Interval = 5000;
                text = GetData();
                timer.Start(); //wait five seconds
                waitEvent.WaitOne();
    
               return text;
            }
    

    Monday, June 16, 2014 9:22 PM
  • Hi

    request 1 - 8s

    request 2 - 13s

    request 3 - 18s

    This was my design issue, I fixed it, and Timer needs to run after call that exe. Here is the code, still it is taking more than 5s to send the response. 

    Here is the code

    private string GetId()
            {
                ManualResetEvent waitEvent = new ManualResetEvent(false);
                string text = string.Empty;
                System.Timers.Timer timer = new System.Timers.Timer();
                timer.Elapsed += (sender, args) =>
                {
                      timer.Stop();
                      timer.Dispose();
                      waitEvent.Set();
                };
                timer.Interval = 5000;
                
                timer.Start(); //wait five seconds
                waitEvent.WaitOne();
                text = GetData();
    
               return text;
            }

    Something wrong with ManualResetEvent ???

    I remove execute exe and tried Magnas method to get responses. The below results without it,,,



    chapneox

    Tuesday, June 17, 2014 6:35 AM
  • This approach seems like a complex equivalent to Thread.Sleep(). ManualResetEvent.WaitOne() still blocks the thread, and its exactly this syncronous style of blocking the thread that is limiting thoughput.

    As long as you block the thread (one way or another), you're going to have the same problem.

    Tuesday, June 17, 2014 12:25 PM