Git Product home page Git Product logo

fastflow's Introduction

Fast Flow

Simple, light and very fast workflow engine which perform sequential, parallel and asynchronous tasks in thread pool executor. Where workflow is bunch of tasks and forks.

What is not implemented?

There is no joins in fast flow but forks only. There is no conditional transitions but unconditional only.

What is special?

It is multi-threaded and very fast! Almost same fast as LMax Disruptor because of non blocking thread synchronization. Actually internal aka Runnable engine of Fast Flow project was inspired by exelent article of Federico Peralta "The bounds of java". That is great contribution to the open source community Federico! Thanks a lot!

Since LMax Disruptor get announced by LMax multi-threading become a downtrend way of doing high performance programming. Lets get it back! We are leaving in the world of multi-core CPU! By the way nothing can stop you from using thread pool executor with one thread only...

Big idea

The Big Idea is switching from MVC toward MVW where classic controller done vie workflow! There are lots of advantages from this approach like easy parallel programming (as simple as sequential), controller logic visualization (like any workflow does), task unification etc. Lets get out from hard-coded controller in your next project!

Sequential execution

Sequential execution starts by executing the first task and continue by executing next task in sequence. Usually it requires one thread only. But fast flow executes them most likely in separate threads with non-blocking synchronization in between. It starts given task first then as soon as task ends execute next one from the sequence in another thread...

alt text

Parallel execution

For given number of parallel tasks we need same amount of threads to run them all in parallel aka simultaneously or concurrently. Depends mostly on how many CPU cores are in place. Summarize all that pros and cons fast flow sets size of thread pool exactly same as number of CPU cores. Then place all parallel tasks into executor's queue. As soon as last task ends fast flow executes next one from the parent flow without blocking parent thread at all!

alt text

If you are single thread adherent or LMax Disruptor follower just set up thread pool having one thread only. Fast flow guarantees all work be done regardless complexity of task composition in your flow.

Here is most simple way to try fast flow:

	FastFlow<Object> ff = new FastFlow<Object>();
	
	FwFlow<Object> hello = ff.sequential.combine(
			(a,b,c,d)->System.out.print("Hello"),
			(a,b,c,d)->System.out.print(","),
			(a,b,c,d)->System.out.print("World"),
			ff.parallel.combine(
					(a,b,c,d)->System.out.print("!"),
					(a,b,c,d)->System.out.print("!")
			),
			(a,b,c,d)->System.out.println("")
		);
	
	hello.start(null);
	
	ff.shutdown();

The log is:

	Hello,FastFlow!!

Bit verbose lambda (a,b,c,d)->{} is the price for non-blocking synchronization implemented in fast flow. None of args are really matter except first one A - it is the context object provided in hello.start(null) method i.e. null.

Hello flow combines 4 sequential tasks and 2 parallel tasks which can be represented by 2 level flow tree. Next example of slightly modified famous 99 Bottle song much more complicated and finally can be represented by 100 level tree of sequential->parrallel->sequential->parallel->*** flow tree.

There are 3 implementations of this demo: vie blocking synchronization with 99 available threads, vie non-blocking synchronization with couple threads and vie non-blocking synchronization with 1 thread only.

As expected blocking implementation get hangs on the last bottle because it requires minimum 100 threads in the executor's pool to be available!

100 bottles of beer on the wall, 100 bottles of beer.
Take one down, pass it around, la, lA, La, LA, 99 bottles of beer on the wall, 99 bottles of beer.
***
Take one down, pass it around, la, lA, La, LA, 1 bottles of beer on the wall, 1 bottles of beer.
Take one down, pass it around, === hangs!!! ===

Scheduled 495 tasks
Completed 495 tasks
Aborted 4 tasks
Max wait 99 tasks
Thread pool size 99

Non-blocking implementations works fine on any pool with greater then 0 available threads.

Here is 8-threads fast flow log:

100 bottles of beer on the wall, 100 bottles of beer.
Take one down, pass it around, la, lA, La, LA, 99 bottles of beer on the wall, 99 bottles of beer.
***
Take one down, pass it around, lA, la, LA, La, 1 bottles of beer on the wall, 1 bottles of beer.
Take one down, pass it around, la, La, lA, LA, No more bottles of beer on the wall, no more bottles of beer.
We've taken them down and passed them around; now we're drunk and passed out!

Scheduled 702 tasks
Completed 702 tasks
Max wait 8 tasks
Max pool size 8

Here is 1-thread fast flow log:

***
We've taken them down and passed them around; now we're drunk and passed out!

Scheduled 702 tasks
Completed 702 tasks
Max wait 1 tasks
Max pool size 1

Flow context is any java object provided in flow run method which propagates among all tasks. Here is another hello flow with HelloContext:

public class HelloTask implements FwTask<HelloContext> {

	/*
	 * Flow context represents bunch of properties of running flow 
	 */
	static public class HelloContext {
		public AtomicInteger counter = new AtomicInteger(0); 
	}

	public String phrase; 
	public HelloTask(String phrase) {
		this.phrase = phrase;
	}

	/*
	 * Flow task implementation has just A parameter - flow context
	 */
	@Override
	public void job(HelloContext context) {
		System.out.printf("%d) %s\n", context.counter.incrementAndGet(), phrase);
	}

	
	public static void main(String[] args) throws InterruptedException {
		
		FastFlow<HelloContext> ff = new FastFlow<HelloContext>();
		
		FwFlow<HelloContext> hello = ff.sequential.combine(
				new HelloTask("Hello"),
				new HelloTask(","),
				new HelloTask("World"),
				ff.parallel.combine(
						new HelloTask("!"),
						new HelloTask("!")
				),
				new HelloTask("")
			);
		
		hello.start(new HelloContext());
		
		ff.shutdown();
	}

}

Here is the log:

1) Hello
2) ,
3) World
4) !
5) !
6) 

Lets run this complex flow 2,000 times and determine execution duration per 1 flow:

Publisher(s) HighOrder (blocking)
#60 threads
FastFlow
#8 threads
FastFlow+RingBuffer
#8 threads
1 thread 35 mls 4 mks 0.5 mks
2 threads 79 mls 9 mks 1.5 mks
4 threads 133 mls 16 mks 6.0 mks
8 threads 100 mls 79 mks 35.5 mks

Is not it that fast! Fast flow without thread blocking 1000'th time faster then thread blocking algo. Modified FastFlow with LMax Ring Buffer in thread pool even more faster! Meanwhile thread blocking algo require 60 threads in the pool minimum otherwise it will hang with 8 publishers.

Fast Flow Perfomance

Perfomance calculated as = Log10( 1/duration ) where duration is the time of execution one complex flow. Actual time is vary from 0.5 mks to 100 mls per flow by the way. Test is done on Intel(R) 8 core CPU i7-4770 @3.4 GHz. alt text

So far the absolute perfomance winner is 1 thread in executor's thread pool per 1 flow publisher. Flow publisher executes the same workflow 40,000 times. If amount of publishers grow up then amount of executed workflows grow up then perfomance getting down obviously. But still highest one achived by 1 thread in the pool. That is why LMax Desruptor absolute highest perfomance pattern! While increasing thread pool size up to 8 threads perfomance getting down to its minimum around 4-8 threads. If you continue increasing pool size then perfomance getting local maximum around 8-32 threads. Over 32 threads we can consider perfomance as a constant.

Why so? Why we still trying parallel programming? How to calculate optimal amount of threads in executor's pool for specific CPU and for certain amount of clients aka publishers? Can answer here...

Asynchronous execution

Along with sequential and parallel task executors there is one more - asynchronous. Works exactly same way as parallel but without any thread synchronization at all - parent task starts and forget all asynchronous children.

Actually composition of sequential and asynchronous tasks running on 2 threads only equivalent to Disruptor Flow engine from my github. Lets compare their performance for the same flow running 1,000,000 times:

Publisher(s),
mks
DisruptorFlow
#2 threads
HighOrder (blocking)
#2 threads
FastFlow
#8 threads
FastFlow+RingBuffer
#8 threads
1 thread 0.08 0.25 1.3 0.33
2 threads 0.3 3.8 3.8 1.8
3 threads 0.5 4.2 6.7 3.5
4 threads 0.7 5.0 9.9 3.1
8 threads 3.3 11.8 25.5 9.5
16 threads 9.7 21.1 70.0 14.4

So far flow based on LMax Disruptor 3-5 times faster then anything else! More over High Order implementation slightly faster then Fast Flow!? Why so? There is a reason behind - there is no any blocking synchronization in this flow because no parallel task in it. That is why HifhOrder faster then regular FastFlow. Modified Fastflow with LMax Ring Buffer in thread pool increase perfomance and put it on the second place after disruptor.

Usage

Since fast flow is not published in any maven repository you can download latest jar or use source code as is.

License is MIT

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.