在多线程应用程序中使用共享的Weka分类器会导致出现异常



我正在运行一个多线程Java应用程序,它接收对实例进行分类的请求。为了能够同时运行多个线程,我的应用程序在线程之间共享Classifier对象和Instances对象。Instances对象只包含属性的相关数据,没有任何与之关联的实例。

当我的应用程序收到分类请求时,我使用请求的属性数据创建一个Instance对象,并使用Instance.setDataset()将预先生成的Instances对象设置为数据集,例如:

myNewInstance.setDataset(sharedInstances);

然后CCD_ 6被发送到共享的CCD_。

它似乎在大多数情况下都很有效。但是,有时当出现两个并发请求时,会从Classifier.distributionForInstance()引发异常。不幸的是,错误消息并不清楚,但我看到了两个不同的例外:

Caused by: java.lang.RuntimeException: Queue is empty
at weka.core.Queue.pop(Queue.java:194)
at weka.filters.Filter.output(Filter.java:563)
at weka.filters.unsupervised.attribute.PrincipalComponents.convertInstance(PrincipalComponents.java:626)
at weka.filters.unsupervised.attribute.PrincipalComponents.input(PrincipalComponents.java:812)
at weka.classifiers.meta.RotationForest.convertInstance(RotationForest.java:1114)
at weka.classifiers.meta.RotationForest.distributionForInstance(RotationForest.java:1147)
Caused by: java.lang.NullPointerException
at weka.filters.unsupervised.attribute.Standardize.convertInstance(Standardize.java:238)
at weka.filters.unsupervised.attribute.Standardize.input(Standardize.java:142)
at weka.filters.unsupervised.attribute.PrincipalComponents.convertInstance(PrincipalComponents.java:635)
at weka.filters.unsupervised.attribute.PrincipalComponents.input(PrincipalComponents.java:812)
at weka.classifiers.meta.RotationForest.convertInstance(RotationForest.java:1114)
at weka.classifiers.meta.RotationForest.distributionForInstance(RotationForest.java:1147)

正如您所看到的,当最近一次发生时,它会附带一个空消息字符串。

据我所知,我不能使对象不可变,为了充分利用并发性,我宁愿不将这一部分封装在关键部分中。我尝试过使用构造函数Instances(Instances dataset)为每个分类请求创建一个不同的"实例"对象,但没有产生不同的结果。使用不同的Classifier不是一种选择,因为构造对象需要花费太多时间,并且需要快速响应(最多10到20毫秒),据我所知,问题并不依赖于此。

我认为问题来自于使用相同的Instances对象。根据Instances的文档,构造函数只复制对标头信息的引用,这解释了为什么没有通过创建另一个对象来解决问题。有没有一个选项可以在不实时查看所有属性的情况下,基于以前的对象创建一个完全不同的Instances对象?

任何其他面向性能的解决方案也将受到高度赞赏。

谢谢!

您现在可能已经解决了这个问题。这只是为那些面临类似问题的人准备的。我在一个多线程Java应用程序中测试实例,遇到了同样的异常。为了解决这个问题,在您的案例中有两个问题:

  • 第一个是使用相同的Instances对象来设置每个请求的数据。这样,您很可能会遇到并发问题,这些问题可能不会破坏代码,但会产生错误的结果。因为来自不同请求的数据可能会混淆。您最好为每个请求创建一个新的Instances对象。然而,这并不是你所面临的例外。这是第二个问题
  • 第二个问题是您使用的是相同的Classifier,这就是产生异常的原因。在我的案例中,我构建了分类器,并将其序列化,并在构建后写入文件。一旦我需要对测试集进行分类,我就习惯于在每个线程中反序列化对象,给我一个新的实例。然而,解决这个问题的一个适当方法是使用weka.classifiers.Classifier.makeCopy(model)静态方法为每个请求制作一个副本,该方法在内部使用序列化

最新更新