Java中的异步开源工作流软件
我有一个系统,有一系列的活动(大约40个)。每个活动要么调用一个服务,要么执行一些计算。这个系统是用Java编写的。目前,所有这些活动都是按顺序执行的,整个过程大约需要2-3秒。我正在尝试优化系统,并尝试减少延迟。我注意到有些活动具有数据依赖性,有些活动是独立的。我试图使这些活动并行运行,同时维护具有数据依赖性的活动序列。例如,假设活动“A”到“F”按以下顺序依次执行:Java中的异步开源工作流软件,java,asynchronous,workflow,pipeline,Java,Asynchronous,Workflow,Pipeline,我有一个系统,有一系列的活动(大约40个)。每个活动要么调用一个服务,要么执行一些计算。这个系统是用Java编写的。目前,所有这些活动都是按顺序执行的,整个过程大约需要2-3秒。我正在尝试优化系统,并尝试减少延迟。我注意到有些活动具有数据依赖性,有些活动是独立的。我试图使这些活动并行运行,同时维护具有数据依赖性的活动序列。例如,假设活动“A”到“F”按以下顺序依次执行: A->B->C->D->E->F (Activities) 1 2 3 4
A->B->C->D->E->F (Activities)
1 2 3 4 5 6 (Time Units)
假设A生成的数据由E使用,B生成的数据由F使用,其余活动不依赖于任何其他数据。我应该能够按照以下顺序并行运行这些活动,而不是按顺序运行这些活动-
A->E
B->F
C
D
1 2 (Time)
因此,系统应该能够在2个时间单位内完成整个过程,而不是6个时间单位。是否有任何开源Java框架可用于处理此类工作流,并在数据可用时无缝执行活动?答案取决于依赖关系图的拓扑结构。如果它可以拆分为独立的线性序列(如示例中所示),那么只需将每个序列表示为可运行序列,并使用各自的线程运行它,或者将它们提交到线程池 如果序列像这样分支:
A->B->C
|
->D->E
然后首先运行序列ABC,然后从活动B运行DE
最复杂的情况是当一个活动依赖于两个或多个活动时:
A->B -> |
C -> |->D // needs both results from B and C
图中需要一个节点,用于收集结果,并在收集所有结果时启动新序列。如果使用线程,则可以将每个依赖项表示为阻塞队列,并使用BlockingQueue.take()
方法让依赖活动首先从所有输入队列中读取。如果使用线程池,则可以:
- 使用Java8
类及其方法CompletableFuture
(用于2个依赖项)或runaftertwo
(用于任意数量的依赖项)allOf
- 使用一些数据流库(作为作者,我推荐)
- 自己实现加入节点,这没什么大不了的
A->B->C
|
->D->E
然后首先运行序列ABC,然后从活动B运行DE
最复杂的情况是当一个活动依赖于两个或多个活动时:
A->B -> |
C -> |->D // needs both results from B and C
图中需要一个节点,用于收集结果,并在收集所有结果时启动新序列。如果使用线程,则可以将每个依赖项表示为阻塞队列,并使用BlockingQueue.take()
方法让依赖活动首先从所有输入队列中读取。如果使用线程池,则可以:
- 使用Java8
类及其方法CompletableFuture
(用于2个依赖项)或runaftertwo
(用于任意数量的依赖项)allOf
- 使用一些数据流库(作为作者,我推荐)
- 自己实现加入节点,这没什么大不了的
- 这是一个专门用于此目的的框架(称为),您可以参考和阅读有关此用例示例的文章。有关类似于用例的工作流,请参阅
下面是如何使用Dexecutor
DexecutorConfig<String, String> config = new DexecutorConfig<>(executorService, new TaskProvider());
DefaultDexecutor<String, String> executor = new DefaultDexecutor<String, String>(config);
executor.addDependency("A", "E");
executor.addDependency("B", "F");
executor.addIndependent("C");
executor.addIndependent("D");
executor.execute(ExecutionConfig.NON_TERMINATING);
DexecutorConfig config=new DexecutorConfig(executorService,new TaskProvider());
DefaultDexecutor executor=新的DefaultDexecutor(配置);
遗嘱执行人。添加附属关系(“A”、“E”);
遗嘱执行人。添加从属关系(“B”、“F”);
执行人。额外独立(“C”);
执行人。额外独立(“D”);
executor.execute(ExecutionConfig.NON_终止);
免责声明:我是此框架的所有者这是一个专门用于此目的的框架(称为),您可以参考和阅读有关此用例示例的Dzone文章。有关类似于用例的工作流,请参阅 下面是如何使用Dexecutor
DexecutorConfig<String, String> config = new DexecutorConfig<>(executorService, new TaskProvider());
DefaultDexecutor<String, String> executor = new DefaultDexecutor<String, String>(config);
executor.addDependency("A", "E");
executor.addDependency("B", "F");
executor.addIndependent("C");
executor.addIndependent("D");
executor.execute(ExecutionConfig.NON_TERMINATING);
DexecutorConfig config=new DexecutorConfig(executorService,new TaskProvider());
DefaultDexecutor executor=新的DefaultDexecutor(配置);
遗嘱执行人。添加附属关系(“A”、“E”);
遗嘱执行人。添加从属关系(“B”、“F”);
执行人。额外独立(“C”);
执行人。额外独立(“D”);
executor.execute(ExecutionConfig.NON_终止);
免责声明:我是此框架的所有者我认为这很难维护。工作流引擎应该是声明式的,而不是命令式的。在我看来,这很难维护。工作流引擎应该是声明式的,而不是命令式的。