Re: concurrency, threads and objects
This is a multi-part message in MIME format.
--------------000905050200090906090608
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Robert Klemme wrote:
On 16.11.2006 18:45, Tom Forsmo wrote:
As far as I understand it. On Windows processes are expensive while
threads are cheap. On linux processes are cheap and threads are
extremely cheap.
Yep, threads on modern systems are very cheap. I once cooked up a small
program (attached) to collect thread stats.
I ran you program on my machine in both windows and linux and discovered
some interesting results:
The machine is a dual boot Thinkpad T60 with intel dual core. no special
systems/kernel optimisations has been performed on either systems.
linux: vanilla linux 2.6.17.8 kernel release running on Mandriva 2006
windows: factory installed windows xp with SP 2 (version 2002)
tf - linux:
max t11 - start time in thread: 55
avg t11 - start time in thread: 0.16632
max t2 - creation time : 42
avg t2 - creation time : 0.02114
max t3 - start time in main : 42
avg t3 - start time in main : 0.09306
max t11 - start time in thread: 65
avg t11 - start time in thread: 0.15874
max t2 - creation time : 15
avg t2 - creation time : 0.01887
max t3 - start time in main : 15
avg t3 - start time in main : 0.09395
tf - windows:
max t11 - start time in thread: 78
avg t11 - start time in thread: 0.66997
max t2 - creation time : 78
avg t2 - creation time : 0.14944
max t3 - start time in main : 63
avg t3 - start time in main : 0.27753
max t11 - start time in thread: 47
avg t11 - start time in thread: 0.73756
max t2 - creation time : 47
avg t2 - creation time : 0.14407
max t3 - start time in main : 47
avg t3 - start time in main : 0.29903
Conclusion: linux is faster.
I also tested a thread efficiency program I made, its a udp server and
client.
server: -t 1000 (number of threads: 1000)
client: -t 500 -r 10000 (number of threads 500,
number of requests per thread: 10000)
tf - linux
Average creation time for client object: 0.00462ms
Time executing threads: 183114ms (183.114s)
Average creation time for client object: 0.00426ms
Time executing threads: 182486ms (182.486s)
tf - windows
Average creation time for client object: 0.00359ms
Time executing threads: 535891ms (535.891s)
Average creation time for client object: 0.00296ms
Time executing threads: 536219ms (536.219s)
conclusion: windows is faster at creating client objects by a little
bit, but linux is 3 times faster at executing the actual operations.
I did another test with this code also:
in the server there is a sleep() call to simulate db access, I
experimented a bit with what values it could hold and how it would
affect the total performance. I found out that the performance
increasement is proportional to the sleep time decreasement, and that
all values down to 1ms (since it is the lowest value for the call I
made) affected performance. But for windows the story was completely
different, why that is I dont know. In windows any values below
100-110ms was rounded up to approx 100ms. So I could not get any
performance increase with values below 100ms. Also there was a strange
spike at the 1ms and 2ms tests (it might have something to do with
kernel context switching thresholds)
Here are the measurements:
tf - windows:
1ms:
E:\threads_perf>java -cp . tf.StatelessUdpClient -t 500 -r 10000
Time executing threads: 453875ms (453.875s)
Time executing threads: 483859ms (483.859s)
2ms:
Time executing threads: 656609ms (656.609s)
Time executing threads: 684734ms (684.734s)
4ms:
Time executing threads: 572547ms (572.547s)
Time executing threads: 604500ms (587.5s)
30ms:
Time executing threads: 578796ms (578.796s)
Time executing threads: 555860ms (555.86s)
100ms:
Time executing threads: 571079ms (571.079s)
Time executing threads: 593531ms (593.531s)
120ms:
Time executing threads: 632657ms (632.657s)
Time executing threads: 639125ms (639.125s)
150ms:
Time executing threads: 773750ms (773.75s)
Time executing threads: 771406ms (771.406s)
200ms:
Time executing threads: 1019234ms (1019.234s)
Time executing threads: 1021328ms (1021.328s)
500ms:
Time executing threads: 2543078ms (2543.078s)
Time executing threads: 2544656ms (2544.656s)
The code is attached.
tom
--------------000905050200090906090608
Content-Type: text/x-java;
name="StatelessUdpClient.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="StatelessUdpClient.java"
package tf;
import java.util.Random;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.Socket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
public class StatelessUdpClient {
public static class StatelessUdpTestClient extends Thread {
private int requestsPerThread = 100;
private int port = 3000;
public StatelessUdpTestClient(int requests) {
this.requestsPerThread = requests;
}
public void run() {
Random rand = new Random();
int requests = requestsPerThread;
try {
DatagramSocket s = new DatagramSocket();
s.setSoTimeout(3000);
int len = 1024;
byte[] buf;
byte[] buf2 = new byte[len];
String status;
boolean reExec = false;
while(requests-- > 0) {
int val = rand.nextInt(1000000000);
String str = new String(Integer.toString(val));
buf = str.getBytes();
DatagramPacket p = new DatagramPacket(buf, buf.length, InetAddress.getByName("localhost"), port);
s.send(p);
DatagramPacket p2 = new DatagramPacket(buf2, len);
try {
s.receive(p2);
} catch (SocketTimeoutException soe) {
reExec = true;
}
if(reExec) {
reExec = false;
// System.out.println("Request timeout, restarting request " + requests);
continue;
}
int ret_val = Integer.parseInt( new String(p2.getData(), 0, p2.getLength()) );
int new_val = val + 1;
if (new_val != ret_val) {
System.out.println(Thread.currentThread().getName() +
" - sent value: " + val + " - return value: " + ret_val +
" new value: " + new_val + " *** FAILED ***");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void exec(int threads, int requests) throws Exception {
long average = 0;
int c = 100000;
StatelessUdpTestClient client = null;
for (int i=0; i<c; i++) {
long t1 = System.currentTimeMillis();
client = new StatelessUdpTestClient(requests);
long t2 = System.currentTimeMillis();
average += t2 - t1;
}
System.out.println("Average creation time for client object: " + (((double) average) / c) + "ms" );
client = new StatelessUdpTestClient(requests);
Thread[] thr = new Thread[threads];
long t3 = System.currentTimeMillis();
try {
for(int i=0; i<threads; i++) {
thr[i] = new Thread(client);
thr[i].start();
}
} catch (Exception e) {
e.printStackTrace();
}
for ( Thread t : thr ) {
try {
t.join();
}
catch ( InterruptedException e ) {
e.printStackTrace();
}
}
long t4 = System.currentTimeMillis();
long threadTime = (t4 - t3);
System.out.println("Time executing threads: " + threadTime + "ms (" + (((double) threadTime) / 1000) + "s)");
}
public static void main(String[] args) throws Exception {
int threads = 10;
int requests = 10;
for(int i=0; i< args.length; i++) {
String s = args[i];
if (s.equalsIgnoreCase("-t")) {
threads = Integer.valueOf(args[++i]);
}
if (s.equalsIgnoreCase("-r")) {
requests = Integer.valueOf(args[++i]);
}
}
StatelessUdpClient.exec(threads, requests);
StatelessUdpClient.exec(threads, requests);
}
}
--------------000905050200090906090608
Content-Type: text/x-java;
name="StatelessUdpWorker.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="StatelessUdpWorker.java"
package tf;
import java.util.Random;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
public class StatelessUdpWorker {
public static class StatelessUdpServer extends Thread {
private DatagramSocket s = null;
{
try {
s = new DatagramSocket(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() {
Random rand = new Random();
try {
int len = 8196;
byte[] buf = new byte[len];
while(true) {
DatagramPacket p = new DatagramPacket(buf, len);
s.receive(p);
int plen = p.getLength();
String str = new String(p.getData(), 0, plen);
int val = Integer.parseInt(str);
val++;
/* Imitating talking to an external source with thread blocking. */
sleep(rand.nextInt(2));
String str2 = new String(Integer.toString(val));
byte[] buf2 = str2.getBytes();
DatagramPacket p2 = new DatagramPacket(buf2, buf2.length, p.getAddress(), p.getPort());
s.send(p2);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void execSingle(int threads) {
StatelessUdpServer wrk = new StatelessUdpServer();
try {
for(int i=0; i<threads; i++) {
new Thread(wrk).start();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished starting threads");
}
public static void execMultiple(int threads) {
try {
for(int i=0; i<threads; i++) {
new StatelessUdpServer().start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
int threads = 10;
for(int i=0; i< args.length; i++) {
String s = args[i];
if (s.equalsIgnoreCase("-t")) {
threads = Integer.valueOf(args[++i]);
}
}
StatelessUdpWorker.execSingle(threads);
// StatelessUdpWorker.execMultiple(threads);
}
}
--------------000905050200090906090608
Content-Type: text/x-java;
name="ThreadCreationOverhead.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="ThreadCreationOverhead.java"
package klemme;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
public class ThreadCreationOverhead {
private static final int THREADS = 100000;
private static class Maximizer {
private long max = 0;
private long sum = 0;
private int count = 0;
public synchronized void update( long n ) {
if ( n > max ) {
max = n;
}
sum += n;
++count;
}
public synchronized long getMax() {
return max;
}
public synchronized double getAvg() {
return ( ( double ) sum ) / count;
}
}
private static void print( String msg ) {
// System.out.println( Thread.currentThread().getName() + ": " + msg );
}
private static void testRun() {
final Maximizer mt11 = new Maximizer();
final Maximizer mt2 = new Maximizer();
final Maximizer mt3 = new Maximizer();
List<Thread> threads = new Vector<Thread>();
for ( int i = 0; i < THREADS; ++i ) {
// System.out.println( "Run " + i );
final long t1 = System.currentTimeMillis();
Thread th = new Thread(
new Runnable() {
public void run() {
long t11 = System.currentTimeMillis() - t1;
mt11.update( t11 );
print( "in thread: " + t11 );
}
} );
long t2 = System.currentTimeMillis() - t1;
th.start();
long t3 = System.currentTimeMillis() - t1;
mt2.update( t2 );
print( "after creation: " + t2 );
mt3.update( t3 );
print( "after start: " + t3 );
// System.out.println();
threads.add( th );
}
for ( Iterator iter = threads.iterator(); iter.hasNext(); ) {
Thread th = ( Thread ) iter.next();
try {
th.join();
}
catch ( InterruptedException e ) {
e.printStackTrace();
}
}
System.out.println( "max t11 - start time in thread: " + mt11.getMax() );
System.out.println( "avg t11 - start time in thread: " + mt11.getAvg() );
System.out.println( "max t2 - creation time : " + mt2.getMax() );
System.out.println( "avg t2 - creation time : " + mt2.getAvg() );
System.out.println( "max t3 - start time in main : " + mt3.getMax() );
System.out.println( "avg t3 - start time in main : " + mt3.getAvg() );
}
public static void main( String[] args ) {
testRun();
System.out.println();
testRun();
}
}
--------------000905050200090906090608--