Yeah, that makes sense. Alexey 2001 Honda CBR600F4i (CCS) 1992 Kawasaki EX500 http://azinger.blogspot.com http://bsheet.sourceforge.net http://wcollage.sourceforge.net
--- On Fri, 11/14/08, Ben Schulz <[EMAIL PROTECTED]> wrote: > From: Ben Schulz <[EMAIL PROTECTED]> > Subject: [The Java Posse] Re: single-threaded vs concurrent performance on > dual-core > To: "The Java Posse" <[email protected]> > Date: Friday, November 14, 2008, 7:00 PM > Playing one round is probably in the (low) 10E2 ticks, so in > relative > terms synchronization overhead of the thread pool is > probably pretty > high compared to the non existent synchronization overhead > of the > single threaded executor > > With kind regards > Ben > > On 14 Nov., 23:36, Alexey Zinger > <[EMAIL PROTECTED]> wrote: > > Sure, I realize how difficult it is to assess these > things, especially sight unseen. I was mostly fishing to > see if there was a known issue with the concurrency API or > anything like that. > > > > But let me answer your questions and I'll post the > part that invokes concurrency as well. > > > > At the moment I don't have access to a Linux box, > but I'll see if I can get this stuff run on one. > > > > Not synchronizing on anything. When I posted the > output, I was in fact using Math.random() API, which, > according to the JDK Javadocs, can synchronize, so I > switched to using java.util.Random.nextInt(int) off a > separate Random object, which is what the Javadoc tells you > to do if you're running in multiple threads. That > actually hurt the single-threaded run by a few seconds and > didn't seem to affect the concurrent mode. > > > > I've run it in both server and client mode with > not perceptible difference. I've also experimented > with different heap allocations, which seems mostly to > affect the concurrent mode by causing it to run out of heap > if not given enough memory. Otherwise, there doesn't > seem to be much of a difference. > > > > As to the number of threads in concurrent mode, > I've experimented with different setups, but for now > I've settled on running each player as separate Future > objects, so that makes 3 threads in concurrent mode, and > each of those spawns up to separate Future objects for each > game play, limited to 1000 threads in concurrent mode. > > > > Here's the interesting part: > > > > package zinger.goats; > > > > import java.util.*; > > import java.util.concurrent.*; > > > > public class Play > > { > > public static class Tester implements > Callable<String> > > { > > protected final Player player; > > protected final int tries; > > protected final > ExecutorService executor; > > > > public Tester(final Player > player, final int tries, final ExecutorService executor) > > { > > this.player = > player; > > this.tries = > tries; > > this.executor = > executor; > > } > > > > public String call() > > { > > return > Play.testPlayer(this.player, this.tries, this.executor); > > } > > } > > > > public static void main(final String... > args) > > { > > final long startMS = > System.currentTimeMillis(); > > final int tries = > Integer.parseInt(args[0]); > > final int maxThreads = > args.length > 1 ? Integer.parseInt(args[1]) : 1; > > final ExecutorService > testExecutor = maxThreads > 1 ? > > > Executors.newFixedThreadPool(Math.min(3, maxThreads)) : > > > Executors.newSingleThreadExecutor(); > > final ExecutorService > gameExecutor = maxThreads > 1 ? > > > Executors.newFixedThreadPool(Math.min(maxThreads, tries)) : > > > Executors.newSingleThreadExecutor(); > > try > > { > > final > List<Future<String>> futures = new > ArrayList<Future<String>>(3); > > > futures.add(testExecutor.submit(new Play.Tester(new > RandomPlayer(), tries, gameExecutor))); > > > futures.add(testExecutor.submit(new Play.Tester(new > NeverChangePlayer(), tries, gameExecutor))); > > > futures.add(testExecutor.submit(new Play.Tester(new > AlwaysChangePlayer(), tries, gameExecutor))); > > > for(Future<String> future : futures) > > { > > try > > { > > > System.out.println(future.get()); > > } > > > catch(final InterruptedException ex) > > { > > > ex.printStackTrace(); > > } > > > catch(final ExecutionException ex) > > { > > > ex.printStackTrace(); > > } > > } > > } > > finally > > { > > > System.out.println("Execution time: " + > ((System.currentTimeMillis() - startMS) / 1000L) + > "sec."); > > > testExecutor.shutdown(); > > > gameExecutor.shutdown(); > > } > > } > > > > public static String testPlayer(final > Player player, final int tries, final ExecutorService > executor) > > { > > final StringBuilder sb = new > StringBuilder(); > > int carCount = 0; > > int goatCount = 0; > > final int[] carDistribution = > new int[3]; > > final int[] goatDistribution = > new int[3]; > > > > final List<Game> games = > new ArrayList<Game>(tries); > > final > List<Future<?>> futures = new > ArrayList<Future<?>>(tries); > > for(int i = 0; i < tries; > ++i) > > { > > final Game game = > new Game(player, new Random()); > > games.add(game); > > > futures.add(executor.submit(game)); > > } > > > > for(int i = 0; i < tries; > ++i) > > { > > try > > { > > > futures.get(i).get(); > > } > > catch(final > InterruptedException ex) > > { > > > ex.printStackTrace(); > > > continue; > > } > > catch(final > ExecutionException ex) > > { > > > ex.printStackTrace(); > > > continue; > > } > > final Game game = > games.get(i); > > > switch(game.getPrize()) > > { > > case > CAR: > > > ++carCount; > > break; > > > > case > GOAT: > > > ++goatCount; > > break; > > } > > for(int doorIndex > = 0; doorIndex < game.doorView.size(); ++doorIndex) > > { > > final > Game.Door door = game.doorView.get(doorIndex); > > > switch(door.open()) > > { > > > case CAR: > > > ++carDistribution[doorIndex]; > > > break; > > > > > case GOAT: > > > ++goatDistribution[doorIndex]; > > > break; > > } > > } > > } > > > > > sb.append(player.getDescription()).append(" won > ").append(carCount).append(" cars and > ").append(goatCount).append(" goats.\n"); > > sb.append("Cars were > distributed as follows:"); > > for(final int prizeCount : > carDistribution) > > > sb.append('\t').append(prizeCount); > > sb.append("\nGoats > were distributed as follows:"); > > for(final int prizeCount : > goatDistribution) > > > sb.append('\t').append(prizeCount); > > sb.append('\n'); > > return sb.toString(); > > } > > > > } > > > > And here's how it's invoked: > > > > <?xml version="1.0"?> > > <project name="Goats" > default="run"> > > <property name="tries" > value="1000000"/> > > <property name="maxThreads" > value="1000"/> > > > > <target name="init"> > > <mkdir > dir="${basedir}/cls"/> > > </target> > > > > <target name="compile" > depends="init"> > > <javac > destdir="${basedir}/cls" > srcdir="${basedir}/src" > debug="true"/> > > </target> > > > > <target name="run" > depends="compile"> > > <echo message="Tries: > ${tries}; max threads: ${maxThreads}."/> > > <echo > message="Single-threaded..."/> > > <echo/> > > <java > classname="zinger.goats.Play" > classpath="${basedir}/cls" fork="true" > failonerror="true"> > > <!--<jvmarg > value="-Xmx1000m"/>--> > > <jvmarg > value="-server"/> > > <arg > value="${tries}"/> > > </java> > > <echo/> > > <echo > message="Concurrent..."/> > > <java > classname="zinger.goats.Play" > classpath="${basedir}/cls" fork="true" > failonerror="true"> > > <jvmarg > value="-Xmx1000m"/> > > <jvmarg > value="-server"/> > > <arg > value="${tries}"/> > > <arg > value="${maxThreads}"/> > > </java> > > </target> > > </project> > > > > And the latest output: > > > > Tries: 1000000; max threads: 1000. > > Single-threaded... > > > > Random Player won 499013 cars and 500987 goats. > > Cars were distributed as follows: 332940 > 333982 333078 > > Goats were distributed as follows: 667060 > 666018 666922 > > > > Never Change Player won 333605 cars and 666395 goats. > > Cars were distributed as follows: 332908 > 333852 333240 > > Goats were distributed as follows: 667092 > 666148 666760 > > > > Always Change Player won 665827 cars and 334173 goats. > > Cars were distributed as follows: 333435 > 332470 334095 > > Goats were distributed as follows: 666565 > 667530 665905 > > > > Execution time: 30sec. > > > > Concurrent... > > Random Player won 500155 cars and 499845 goats. > > Cars were distributed as follows: 333661 > 334231 332108 > > Goats were distributed as follows: 666339 > 665769 667892 > > > > Never Change Player won 333164 cars and 666836 goats. > > Cars were distributed as follows: 332788 > 333709 333503 > > Goats were distributed as follows: 667212 > 666291 666497 > > > > Always Change Player won 666344 cars and 333656 goats. > > Cars were distributed as follows: 333603 > 333938 332459 > > Goats were distributed as follows: 666397 > 666062 667541 > > > > Execution time: 39sec. > > > > --- On Fri, 11/14/08, Reinier Zwitserloot > <[EMAIL PROTECTED]> wrote: > > > > > From: Reinier Zwitserloot > <[EMAIL PROTECTED]> > > > Subject: [The Java Posse] Re: single-threaded vs > concurrent performance on dual-core > > > To: "The Java Posse" > <[email protected]> > > > Date: Friday, November 14, 2008, 3:03 PM > > > There are a gazillion factors at work here, from > bugs in > > > your code to > > > JVM implementation to kernel thread scheduler. > Without > > > exquisite > > > detail, I don't think its even possible to > shed some > > > light as to why > > > you're seeing a slight (less than doubling is > > > 'slight', in meaningful > > > profiling). Even with all that info, I doubt -I- > could tell > > > you, > > > though I cannot of course speak for other posse > listeners. > > > > > A few quick and dirty ones: > > > > > - try this on linux 2.6. It has a kick ass > thread > > > scheduler. > > > - are you synchronizing on anything, or did you > add > > > Thread.sleep/wait > > > anywhere? That tends to make stuff worse. > > > - are you on the server VM? I don't think > this matters > > > anymore in > > > 6u10, though, as the mixed mode VM is pretty > smart, or so I > > > hear. > > > - are you using exactly 2 threads, slightly > more than > > > that, or a > > > massive amount of them? > > > > > On Nov 14, 7:04 pm, Alexey Zinger > > > <[EMAIL PROTECTED]> wrote: > > > > A little while ago I wrote a simulation of > the Monty > > > Hall puzzle. The simulator is given 3 players > of different > > > strategies (one makes a decision at random, the > other never > > > switches doors, and the third always switches) > and runs each > > > player through a configurable number of games, > outputting > > > each player's outcomes at the end. Seems > fairly simple > > > and everything was working as expected. > > > > > > Seeing as I have a dual core machine (XP > Pro, JRE > > > 1.6_10), I looked at the way the CPU was being > utilized and > > > to my surprise I saw a fairly even utilization of > both > > > cores, despite the program being > single-threaded. Then I > > > decided to make the simulator multi-threaded and > see what > > > would happen to the utilization graph and speed > of the > > > application. I converted the > > > > code invoking the game generation and > running API to > > > use Java concurrency framework, which also game > me good > > > control over how many threads I wanted to use or > if I wanted > > > to run everything single-threaded still. Once I > got > > > everything working again, I was dismayed to see > somewhat > > > uneven > > > > ... > > > > Erfahren Sie mehr » > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "The Java Posse" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/javaposse?hl=en -~----------~----~----~----~------~----~------~--~---
