• Post Reply Bookmark Topic Watch Topic
  • New Topic

Fork/Join on single processor machines  RSS feed

 
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
According to http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html
The fork/join framework is an implementation of the ExecutorService interface that helps you take advantage of multiple processors.


What are the implications of that when running a JVM on a single processor machine (which my PC running Windoze may be...I don't even know to be honest)? I am getting confused now between threads and processes. I can obviously code a Java program that kicks off 100 threads even if I'm running on a single processor CPU....can't I? If so, how does that relate to the above statement?
I would appreciate some illumination on this murky issue.
Thanks very much.

 
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The different executors are used for different purposes. A fork join system is often used when you have a processor intensive app where a task does pretty much nothing but consume cpu time. In this scenario you could create lots of threads but you wouldn't want to because too many threads trying to consume a processor's time, without having natural points of downtime, just get in each other's way.

So a fork join pool is usually used with one thread per processor so each thread has 100% of a processor's time to work with. A normal executor service could be configured the same way, but the unique bit about the fork join pool is that a task is usually started in a single thread, splits itself into multiple sub tasks and queues those tasks in the same thread. When a thread is done with its tasks, instead of sitting idle it takes tasks queued up in other threads so you get better utilization of the processor time.
 
Steven Squeers
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Steve, but what I'm after is an explanation of how fork/join works on single processor machines, given the quoted text.
(edit) Actually maybe you're half-answering that with this:

"a fork join pool is usually used with one thread per processor"

but that doesn't entirely answer the question: how does fork/join work on a *single* processor machine: what should one's expectations be? Is it pointless? Should we not even bother with fork/join on a single processor machine? etc.

Cheers.
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you use the the ForkJoinPool with the default settings, your expectations on a single processor would be at best the same speed as writing the code without using threading, perhaps a bit slower as the task will be broken down into subtasks which probably takes some non-0 amount of time. You would expect there to be one thread, and that thread to be used to process all the subtasks in sequence. If you use one of the ForkJoinPool constructors that requires a parallelism parameter and you don't provide Runtime.availableProcessors() as the argument, then you would expect the behavior to be different depending on the task and the parallelism you provide (for example, a high CPU usage task, with parallelism > # of CPUs may mean decrease of performance, but really only performance tuning and knowledge of the task will be needed to determine the effects for real.)

you should not write your program to maximize performance on a single CPU even if that is the environment you have, unless you are sure that is the only environment the application will ever be run on. Computers that have only a single CPU/processing unit are rare nowadays and you would be shooting yourself in the foot if you write your app with that assumption. As a naive first attempt, I would consider the task and run it by itself in a single thread. Analyze the percent of CPU used during the processing, and if you are > 90% CPU use through the course of the task, without breaks, pauses, or blocks, and the task is amenable to being broken down to subtasks I would use the ForkJoinPool and run another test. I would then expect the same sort of CPU use, and if on a single core machine I would expect it to take about the same amount of time, while if I am on a multi-core system I would expect it to run multiple (or all) CPUs at about the same high level, and the total task to run faster.

In a more sophisticated approach, I would then consider tweaking the parallelism, using some multiple or addition to Runtime.availableProcessors() (for example Runtime.availableProcessors() *1.5 or + 2 ...) to see if I get some speed improvement. I would want to test this tweak on multiple systems if at all possible (single core, multiple core, low memory, high memory...) to make sure the tweak doesn't help in just one limited scenario and there isn't some likely scenario where the combination of processing capabilities and available memory kills performance (and if there is, I would look to solve the problem, either by managing memory, scaling back on the parallelism, or making a minimum spec for running the software.)
 
Steven Squeers
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Great answer. Many thanks Steve.

Cheers
 
Ranch Hand
Posts: 334
2
Java Netbeans IDE Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sounds like fork/join is a Java 8 paradigm, correct?

One situation that hasn't been mention is when the tasks are more I/O bound. Here if the I/O is not all to one local device many tasks per processors can be very effective.

One example is a program I wrote to summarize Apache log files. We didn't have the webserver do the rDNS lookups but did them when parsing the logs. I don't remember exactly but we had 20 or 30 threads doing the lookups and got a speedup of better than the number of threads due to the common occurrence of timeouts.

I also belive most web browsers do this when loading a web page with multiple images.

I do agree with all the comments about compute bound processes.

Joe
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Joe Areeda wrote:Sounds like fork/join is a Java 8 paradigm, correct?
It was introduced in Java 7.

One situation that hasn't been mention is when the tasks are more I/O bound. Here if the I/O is not all to one local device many tasks per processors can be very effective.

Right, significant I/O is one of several things that might make using other threading models more appropriate, because I/O leave gaps in the CPU usage, giving downtime that can best be used by switching thread contexts so some other task can run while the I/O takes place. Synchronization between threads is another sign that fork join is probably not the right tool for pretty much the same reason.
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!