Discussions

Performance and scalability: Thread.sleep() - evil joke.

  1. Thread.sleep() - evil joke. (13 messages)

    Thread.sleep( long milliseconds ) is one of the most evil methods in Java, yet many people need it.

    Why is it evil? Because it is completely unreliable and lies worse than even Fox News. If you do not beleive, just try running this test:

    class Main {
     
            public static void main ( String[] args ) {
     
                    long start, end, took;
     
                    start = System.currentTimeMillis();
                    for ( int i=0; i<200; i++) {
                            try {
                            Thread.sleep (5);
                            } catch ( Exception ex ) {
                                    ex.printStackTrace();
                            }
                    }
                    end = System.currentTimeMillis();
                    took = end -start;
                    System.out.println ("Took: " + took);
     
            }
    }

    Obviously you must be getting 1000, but do not expect anything below 3500. I got 3500-4500 on different runs.

    Why is Thread.sleep() so extremely important? Because, that's how you achieve permanent TPS (Transaction Per Second). At least - you would wish to. If your TPS is anything more than 200 (on Windows) or anything more than 50 (on Linux) - hold your hopes!

    The worst irony is that in JDK5, Sun released Thread.sleep( long millis, int nanos) method.

    They can not get even 10-100 millisecond periods straight, what nanos are they talking about?

    :-(

    Threaded Messages (13)

  2. Thread.sleep() - evil joke.[ Go to top ]

    Because it is completely unreliable and lies worse than ...

    Please state which part of the API documentation is a "lie". You may not like the API, but that is a separate issue.
    Thread.sleep() so extremely important? Because, that's how you achieve permanent TPS (Transaction Per Second). At least - you would wish to.
    I guess that by "you achieve permanent TPS" you mean generate a known transaction rate.

    Firstly you need to understand what is happening in the operating system; the JVM cannot exceed any guarantees made by the OS.

    Secondly you need to decide exactlywhat you are trying to measure and more importantly what you are not worried about. That understanding will probably invalidate your presumption.

    Thirdly, using just sleep(long ms), how are you proposing to generate 750TPS?

    It is fairly straightforward to generate intervals with sub-ms accuracy on a standard Wintel or Linux PC. Hint: think arithmetic mean.
  3. Thread.sleep() - evil joke.[ Go to top ]

    Hey Tom,

    thanks for a reply. I hope you excuse my previous message's attitude after a sleepless night and two days struggling with JVM. And, yes, I do realize OS has its share of blame, too - not that the realization helps anybody, though.

    Now, business..

    A lie, for instance, is in the Javadoc API which states:
    Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds
    No, it does not. With small intervals (e.g. Thread.sleep(5)) it DOES NOT cease the execution for the period indicated. I posted the test code which proves that.

    Now, if messing up on the millisec level is a lie, when they know it does not work even there (and they should know) "introducing" nanoseconds method, I took as a personal offense :-).
    I guess that by "you achieve permanent TPS" you mean generate a known transaction rate.

    Correct.

    Thread.sleep() is important for the generation of known transaction rate, because what I am trying to do looks something like the following code and I am trying to get high TPS:
     ThreadPoolExecutor exec = ( ThreadPoolExecutor) Executors.newCachedThreadPool( new BasicTaskFactory () );

    while ( condition ) {

      SomeRunnableTask t = new SomeRunnableTask();
      exec.execute( t );

      try {
         Thread.sleep (2)
      } catch (InterruptedException e) {
           e.printStackTrace();
      }
    }
    It is fairly straightforward to generate intervals with sub-ms accuracy on a standard Wintel or Linux PC. Hint: think arithmetic mean.
    Can you elaborate on what you mean?

    Thank you
  4. Thread.sleep() - evil joke.[ Go to top ]

    Hmmm, Irakli,

    There are several fallacies in your points. Let me try to explain some without going into CS101. :)

    1) Your OS - You are more than likely running a preemptive OS. Therefore, it is likely that AT LEAST a few millis will be consumed by your OS. When you put a thread to sleep, it will undoubtedly signal the OS to stop servicing the sleeping thread (no need to waste cpu cycles, right?) and go do something else. By the time it "wakes up", the OS may not -immediately- start the thread. For example, running your test on my laptop yields an average around 1200. Funny, that seems to be about 1ms lost per loop, huh? However, when I kick off a bunch of other busy processes and keep the cpu busy while running your test, things go a little slower and I get around 1400 total time. Main point -- your little test thread isn't the ONLY thing your PC is doing.

    2) Java GC - There are things that are occuring in the JVM which you have no control over. There are other threads in a JVM -- Garbage Collection, Timer Threads, etc. If on Windows, do a ctrl-break while a JVM is running or a kill -3 {pid} on *nix box and you'll see a list of all the threads in the JVM. It could be that garbage collection kicked in and all your other threads came to a screaching halt while it did some collection/house-cleaning.

    3) As Tom asked, I've no idea why you are relating your example to TPS? Are you trying to schedule something? Performance testing? If so, then I'd argue why you are trying to be so strict about arrival rates and that your PC appears to be way underpowered.

    4) Are you using a slow PC? What Mhz/RAM? How are you running your JVM.

    5) You're test has a huge error being factored into it. Change it to the following to see what results you get:


    for (int i = 0; i < 20; i++) {
      try {
      long sleepStart = System.currentTimeMillis();
      Thread.sleep(50);
      long sleepTime = (System.currentTimeMillis() - sleepStart);

      System.out.println("Actual sleep time (+some code overhead)=" + sleepTime);

      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }



    -Dustin, who enjoys Fox News. :)
  5. Thread.sleep() - evil joke.[ Go to top ]

    Dustin,

    thanks for a reply. You said so much, so much could be true, it even almost makes sense, yet - none of it has anything to do with reality :)

    Sorry, buddy, next time.

    Now facts.

    When you made that statement about the "overhead" of a loop operator (because there is nothing else there), I sincerely hope you were kidding. Besides your code does not do the same as what mine does.

    The "slow" machine I was running that test on is (suprise, suprise) - a dual opteron (each 2GHz) with 2GB RAM with a completely idle CPU during the test run. Neither was there any business for GC to be doing during this test run.

    And here comes the killer which sends all the rest of the arguments, in defense of JVM makers (because, I tested IBM JDK is equally sinful). And the killer is the following code:
    class Test {

            public static void main ( String[] args ) {

                    long start, end, took;

                    start = System.currentTimeMillis();
                    for ( int i=0; i<200; i++) {
                            try {
                            halt (5);
                            } catch ( Exception ex ) {
                                    ex.printStackTrace();
                            }
                    }
                    end = System.currentTimeMillis();
                    took = end -start;
                    System.out.println ("Took: " + took);

            }

            public static void halt (long millis ) {

                 long start, took;

                 start = System.nanoTime();
                 while ( true ) {
                     float k = (float)(3.14 * 9.1);
                     long nanos = millis * 1000000L;
                     if (( System.nanoTime() - start) > nanos ) break;

                 }
            }
    }

    Take a wild guess what the result of this run is? Exactly 1000 (plus minus one but not 3500 or 4100 like in Thread.sleep()'s case)

    I am sure the source of Thread.sleep() is much more complicated than my pet method halt(), yet - the latter does job way better (or former does not do its job at all).

    So much for "rocket scientists".

    *disgusted*
  6. Thread.sleep() - evil joke.[ Go to top ]

    :) This is fun. Really! But, your _new_ code still jives with my points made above.

    Few points I'd like to make:

    o) Your new code never uses any threading. It just uses a cpu-intensive loop to constantly check the cpu time (probably a gazillion times a second) and exits immediately when the time is exactly N millis from when you started. Since the thread is busy (VERY, VERY BUSY), the thread never pre-empts and things appear to run fine.

    o) I agree, it still sounds very odd that your code on that nice of a box is running in 3.5+ seconds. No doubt, that is odd. However, even with a million-cpu box, your test will have same results -- you are only running a single thread. More importantly, you'd need to supply what your JVM heap config is set to to know if there was a GC issue (although, I would highly doubt it unless you are setting it to run in an itsy-bitsy-teeny-weeny heap??)

    o) Try this: Try taking a few thread dumps while your test is running. Try doing a ctrl-break (if on Windows) or kill -3 {pid} (*nix, of course) to see what your threads are doing. Do you see it sitting in some app code? What is the thread state? What else is going on?

    I still stand by my initial points 100%. :)

    -Dustin
  7. Thread.sleep() - evil joke.[ Go to top ]

    .A lie, for instance, is in the Javadoc API which states:
    Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds
    No, it does not. With small intervals (e.g. Thread.sleep(5)) it DOES NOT cease the execution for the period indicated.

    Please provide proof that the Thread execution continued before 5ms expired, because that is the only lie that could occur.

    I think you are complaining that the Thread did not resume after exactly 5ms. But that is a completely different issue.

    I think you need to go back to school and understand the possible states that any thread or process can be in. Any book on any operating system or any language will do; this isn't a Java issue. Hint: look for keywords such as "Suspended", "Running", "Runnable".

    You say you have a dual Opteron. Suppose you have two threads in your Java code and each one is occupying 100% of a CPU. What happens when an LAN/ethernet packet arrives, or someone presses a key, etc etc etc.
    Then look at your Java process and notice that there are more than 2 threads in that single process, and repeat your analysis.

    Then consider what happens during garbage collection.

    Summary
    Learn to read and understand what any specification is not guaranteeing. (That is particularly useful when buying any form of insurance :). And understand the technology you are using.
  8. Thread.sleep() - evil joke.[ Go to top ]

    "I will not give you a jam sandwich before you have given me $100".

    If you give me $100, do you think I have said I will give you a jam sandwich? Actually I have only said when I won't give you one. You might like to think otherwise, but that's your misinterpretation.
  9. Thread.sleep() - evil joke.[ Go to top ]

    Tom,

    Exactly when did you stop being a lawyer and start being a programmer?


    LOL
  10. Thread.sleep() - evil joke.[ Go to top ]

    Tom,Exactly when did you stop being a lawyer and start being a programmer?LOL

    Is there a significant difference?

    Each tries to understand <X> and use <X> to do something useful in the real world. In both cases <X> is informally specified in a natural language, and is (partly by design) ambiguous. The only difference is whether <X> is created by other lawyers or other programmers.
  11. Re: Thread.sleep() - evil joke.[ Go to top ]

    Hi, class Main { public static void main ( String[] args ) { long start, end, took , threadStart, threadEnd, threadTook, threadTotal=0; start = System.currentTimeMillis(); for ( int i=0; i<1; i++) { threadStart = System.currentTimeMillis(); try { Thread.sleep (2000); } catch ( Exception ex ) { ex.printStackTrace(); } threadEnd = System.currentTimeMillis(); threadTook = threadEnd -threadStart; threadTotal += threadTook; System.out.println ("threadTook: " + threadTook); } end = System.currentTimeMillis(); took = end -start; System.out.println ("Took: " + took); System.out.println ("threadTotal: " + threadTotal); } } This gave me a result exactly like this. Took: 2000 Press any key to continue . . . You increase the iteration limit to more than 10 or 100 and you will get just a little difference and not as dramatic as stated above. Cheers, kalim
  12. Thread.sleep() - evil joke.[ Go to top ]

    It is fairly straightforward to generate intervals with sub-ms accuracy on a standard Wintel or Linux PC. Hint: think arithmetic mean.
    Can you elaborate on what you mean?Thank you
    Get some sleep, relax, consider that big hint and what it implies, and the other things said on this forum,

    Until you have done that I don't have enough time to tell you. After you have done that you will not need me to tell you.
  13. @tom[ Go to top ]

    Tom, You are a complete idiot and making a fool out of yourself. You have not contributed anything to this discussion AT ALL. Shrek2000
  14. Thread.sleep() - evil joke.[ Go to top ]

    Why is Thread.sleep() so extremely important? Because, that's how you achieve permanent TPS (Transaction Per Second).
    That's naive. My employer makes latency marketing claims of ones or tens of milliseconds for a heavily threaded OLTP application for J2SE. You're right to say that sleep() sucks. You're wrong to assume that sleep() was intended for multithread performance. Java has better facilities for that. BTW, if you think sleep() is an evil joke, did you know that yield() and setPriority() are part of a communist plot, and that they offer absolutely no behavioral guarantees -- none!