当多个进程并行运行时,Drools似乎会给出不正确的结果,并且在每个进程中,每次都会创建和处理一个新的KieBase
对象。
试用版本:6.5.0。最终
,7.32.0。最终
细节:
我并行执行了120个任务(使用7个线程)。在这120项任务中,drools对108项任务给出了正确的结果,但对12项任务执行了错误的规则(每次运行失败的任务数量各不相同)。
让我在这里发布代码和输出:
public class TempClass {
public List<String> droolLogging = new ArrayList<>();
}
public void execute(){
Map<String, List<String>> failedTasks = new ConcurrentHashMap<>(); // to see which tasks were incorrectly executed
// Run 120 tasks in parallel using x threads (x depends upon no of processor)
IntStream.range(1, 120).parallel()
.forEach(taskCounter -> {
String uniqueId = "Task-"+taskCounter;
TempClass classObj = new TempClass();
String ruleString = "package com.sample" + taskCounter + "\n" +
"import com.TempClass\n" +
"\n" +\
"rule \"droolLogging"+taskCounter+"\"\n" +
"\t when \n" +
"\t\t obj: TempClass(true)\n" +
"\t then \n" +
"\t\t obj.droolLogging.add(\"RuleOf-"+uniqueId+"\");\n" +
"\t end\n";
// Above ruleString contains 1 rule and it is always executed.
// After execution, it will add an entry in array list 'droolLogging'
// of class 'TempClass'. In this entry, we are storing task counter
// to see rule of which task is executed.
//following line of code seems to be the culprit as this is somehow returning incorrect KieBase sometime.
KieBase kbase = new KieHelper()
.addContent(ruleString, ResourceType.DRL)
.build();
/*
//Same issue occurs even if I create different file with different name instead of using KieHelper.
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
String inMemoryDrlFileName = "src/main/resources/inmemoryrules-" + taskCounter + ".drl";
kfs.write(inMemoryDrlFileName, ruleString);
KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();
KieContainer kContainer = ks.newKieContainer(kieBuilder.getKieModule().getReleaseId());
KieBaseConfiguration kbconf = ks.newKieBaseConfiguration();
KieBase kbase = kContainer.newKieBase(kbconf);
*/
StatelessKieSession kieSession = kbase.newStatelessKieSession();
kieSession.execute(classObj);
System.out.println("(" + Thread.currentThread().getName() + ") " +
uniqueId + "_" + classObj.droolLogging );
//Important:
// To see if correct rule is executed, task no. printed by variable 'droolLogging'
// should match with uniqueId
if(classObj.droolLogging == null || classObj.droolLogging.size() != 1 ||
!classObj.droolLogging.get(0).endsWith(uniqueId)) {
failedTasks.put("" + taskCounter, classObj.droolLogging);
}
});
logger.info("Failed:\n {}", failedTasks);
}
OUTPUT:
(ForkJoinPool.commonPool-worker-1) Task-37_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-6) Task-8_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-3) Task-18_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-2) Task-108_[RuleOf-Task-4]
(main) Task-78_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-7) Task-52_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-4) Task-97_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-5) Task-4_[RuleOf-Task-4]
(ForkJoinPool.commonPool-worker-3) Task-19_[RuleOf-Task-19]
(ForkJoinPool.commonPool-worker-5) Task-5_[RuleOf-Task-5]
(ForkJoinPool.commonPool-worker-2) Task-109_[RuleOf-Task-109]
(ForkJoinPool.commonPool-worker-7) Task-53_[RuleOf-Task-53]
(ForkJoinPool.commonPool-worker-1) Task-38_[RuleOf-Task-38]
(ForkJoinPool.commonPool-worker-4) Task-98_[RuleOf-Task-98]
.... more
Failed (12):
{88=[RuleOf-Task-77], 78=[RuleOf-Task-4], 68=[RuleOf-Task-60], 37=[RuleOf-Task-4], 15=[RuleOf-Task-1], 18=[RuleOf-Task-4], 7=[RuleOf-Task-11], 8=[RuleOf-Task-4], 108=[RuleOf-Task-4], 71=[RuleOf-Task-76], 52=[RuleOf-Task-4], 97=[RuleOf-Task-4]}
This shows:
- Rule of task 77 was executed in task 88
- Rule of task 4 was executed in task 78
- Rule of task 60 was executed in task 68
- ....
This is wrong. For correct results, in each process, Rule of task X should be executed in task X only.
你知道这背后的原因吗?
更新:以上代码仅用于测试目的,以查看KieBase的生成和执行在多线程环境中的行为。实际用例如下:
我们有一套分类规则。对于每个类别,需要执行特定的规则集。
Example:
for category 1 , I need to execute rule101, rule102, rule103
for category 2 , I need to execute rule201, rule202, rule203
....
Note: During evaluation, rules of category X should NOT interfere with Rules of category Y, i.e., they should be run independently.
由于类别数量巨大,我们正在为每个类别并行构建Kiebase,并将其存储x分钟。x分钟后,我们检查任何类别的规则是否已更改,如果更改,将为这些类别再次编译KieBase(这将再次并行)。
此外,可以在运行时添加新类别。因此,对于新添加的类别,也遵循上述过程。
category1 -> KieBase1 (compiled rules: rule101, rule102, rule103)
category2 -> KieBase2 (compiled rules: rule201, rule202, rule203)
category3 -> KieBase3
Note: As already mentioned above, execution of KieBase X should NOT interfere with execution of KieBase Y as KieBases are created category wise and for each category, only particular set of rules should be executed.
最后证明这是Drools中的一个错误,因为KieHelper
在多线程环境中使用不安全。
在Drools开发社区的一位成员提出解决方案后,以下似乎是上述异常的原因以及克服此问题的解决方法:
问题的根本原因:KieHelper使用相同的默认releaseId构建KieModule。
解决方案:为每个构建使用不同的发布ID。
代码:(在上面提到的代码中使用它)
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
kfs.write("src/main/resources/rules.drl", ruleString);
ReleaseId releaseId = ks.newReleaseId("com.rule", "test" + taskCounter, "1.0.0");
kfs.generateAndWritePomXML(releaseId);
KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll();
Results results = kieBuilder.getResults();
if (results.hasMessages(Message.Level.ERROR)) {
throw new RuntimeException(results.getMessages().toString());
}
KieContainer kContainer = ks.newKieContainer(releaseId);
KieBase kbase = kContainer.newKieBase(ks.newKieBaseConfiguration());
StatelessKieSession kieSession = kbase.newStatelessKieSession();
kieSession.execute(classObj);
通过运行验证
问题内容: 我正在做一个游戏,但是每当我运行第二个jFrame时,我都必须调整它的大小才能获得第二个jFrame的正确大小,有人知道为什么吗? 这是第一个jFrame类中的方法,它将打开第二个类: 这是第二个jFrame类,我必须重新调整它的大小才能正确显示山雀: 问题答案: 我读得很快,正在寻找一种特定的方法。 该方法是: JFrame中的此方法可能非常有用,但也很难处理,您需要非常了解如何设置
我在同一个drl文件中有两个Drools规则,如下所示: 我的想法是用第一条规则处理所有处于临界状态的事件。然后使用第二个规则,如果任何阀门有警报,这是由“如果临界”规则设置的,发送一个短信。 你知道吗?用口水可能吗?
问题内容: 我正在我的VirtualBoxed Ubuntu 11.4上测试此Go代码 Ubuntu可以访问我所有的4个内核。我通过同时运行几个可执行文件和系统监视器来检查这一点。但是,当我尝试运行此代码时,它仅使用一个内核,并且没有从并行处理中获得任何收益。 我做错了什么? 问题答案: 您可能需要查看Go FAQ 的Concurrency部分,特别是以下两个问题,并确定哪个(如果不是两个)适用于
我使用Drools6.1.0.final和一个无状态会话来激发所有规则。 在我的.drl文件中有以下两个简单的规则。 我想这样做:如果第一个规则为true,则不执行任何其他规则,并从。drl文件退出。 我试着如下: > 试图在第一个规则的Then块中抛出运行时异常,但由于NullPointerException的原因,它仍然会在第二个规则中失败。 添加了drools.halt()和kcontext
问题内容: 我在Python中遇到一个奇怪的问题:除法未正确执行: 结果如下: 谢谢 问题答案: 上面的行为对于Python 2是正确的。Python 3中的行为已得到修复。在Python 2中,您可以使用: 然后用来获得您想要的结果。 由于要除以两个整数,因此得到的结果是整数。 或者,将数字之一更改为。
我有这样的情况,在规则文件中的所有规则必须检查执行。如果我的理解是正确的,文档所说的规则将由引擎任意执行。 我有一个或多个疑问。 > 我在许多地方得到了答案,我必须使用显著性功能来按顺序执行它们。如果我使用显著性,并且我有执行所有规则的要求,它真的会大规模地影响性能吗?如果是,它会如何影响性能,甚至规则引擎也会任意执行所有规则,比如一些随机顺序。 提前谢谢。